xref: /openbmc/linux/net/core/pktgen.c (revision 6f107c741212ca5fbfb0724571395716420017d6)
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
728788370aSJesper Dangaard Brouer  * way.
738788370aSJesper Dangaard Brouer  * The if_list is RCU protected, and the if_lock remains to protect updating
748788370aSJesper Dangaard Brouer  * of if_list, from "add_device" as it invoked from userspace (via proc write).
751da177e4SLinus Torvalds  *
761da177e4SLinus Torvalds  * By design there should only be *one* "controlling" process. In practice
771da177e4SLinus Torvalds  * multiple write accesses gives unpredictable result. Understood by "write"
781da177e4SLinus Torvalds  * to /proc gives result code thats should be read be the "writer".
79b4099fabSStephen Hemminger  * For practical use this should be no problem.
801da177e4SLinus Torvalds  *
811da177e4SLinus Torvalds  * Note when adding devices to a specific CPU there good idea to also assign
821da177e4SLinus Torvalds  * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU.
831da177e4SLinus Torvalds  * --ro
841da177e4SLinus Torvalds  *
851da177e4SLinus Torvalds  * Fix refcount off by one if first packet fails, potential null deref,
861da177e4SLinus Torvalds  * memleak 030710- KJP
871da177e4SLinus Torvalds  *
881da177e4SLinus Torvalds  * First "ranges" functionality for ipv6 030726 --ro
891da177e4SLinus Torvalds  *
901da177e4SLinus Torvalds  * Included flow support. 030802 ANK.
911da177e4SLinus Torvalds  *
921da177e4SLinus Torvalds  * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
931da177e4SLinus Torvalds  *
941da177e4SLinus Torvalds  * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
951da177e4SLinus Torvalds  * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
961da177e4SLinus Torvalds  *
971da177e4SLinus Torvalds  * New xmit() return, do_div and misc clean up by Stephen Hemminger
981da177e4SLinus Torvalds  * <shemminger@osdl.org> 040923
991da177e4SLinus Torvalds  *
100ca9f1fd2SStephen Hemminger  * Randy Dunlap fixed u64 printk compiler warning
1011da177e4SLinus Torvalds  *
1021da177e4SLinus Torvalds  * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
1031da177e4SLinus Torvalds  * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
1041da177e4SLinus Torvalds  *
1051da177e4SLinus Torvalds  * Corrections from Nikolai Malykh (nmalykh@bilim.com)
1061da177e4SLinus Torvalds  * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
1071da177e4SLinus Torvalds  *
1081da177e4SLinus Torvalds  * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
1091da177e4SLinus Torvalds  * 050103
110ca6549afSSteven Whitehouse  *
111ca6549afSSteven Whitehouse  * MPLS support by Steven Whitehouse <steve@chygwyn.com>
112ca6549afSSteven Whitehouse  *
11334954ddcSFrancesco Fondelli  * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
11434954ddcSFrancesco Fondelli  *
115ce5d0b47SAdit Ranadive  * Fixed src_mac command to set source mac of packet to value specified in
116ce5d0b47SAdit Ranadive  * command by Adit Ranadive <adit.262@gmail.com>
117ce5d0b47SAdit Ranadive  *
1181da177e4SLinus Torvalds  */
119f9467eaeSJoe Perches 
120f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
121f9467eaeSJoe Perches 
1221da177e4SLinus Torvalds #include <linux/sys.h>
1231da177e4SLinus Torvalds #include <linux/types.h>
1241da177e4SLinus Torvalds #include <linux/module.h>
1251da177e4SLinus Torvalds #include <linux/moduleparam.h>
1261da177e4SLinus Torvalds #include <linux/kernel.h>
127222fa076SLuiz Capitulino #include <linux/mutex.h>
1281da177e4SLinus Torvalds #include <linux/sched.h>
1291da177e4SLinus Torvalds #include <linux/slab.h>
1301da177e4SLinus Torvalds #include <linux/vmalloc.h>
1311da177e4SLinus Torvalds #include <linux/unistd.h>
1321da177e4SLinus Torvalds #include <linux/string.h>
1331da177e4SLinus Torvalds #include <linux/ptrace.h>
1341da177e4SLinus Torvalds #include <linux/errno.h>
1351da177e4SLinus Torvalds #include <linux/ioport.h>
1361da177e4SLinus Torvalds #include <linux/interrupt.h>
1374fc268d2SRandy Dunlap #include <linux/capability.h>
1382bc481cfSStephen Hemminger #include <linux/hrtimer.h>
13909fe3ef4SAndrew Morton #include <linux/freezer.h>
1401da177e4SLinus Torvalds #include <linux/delay.h>
1411da177e4SLinus Torvalds #include <linux/timer.h>
142cdcdbe0bSLuiz Capitulino #include <linux/list.h>
1431da177e4SLinus Torvalds #include <linux/init.h>
1441da177e4SLinus Torvalds #include <linux/skbuff.h>
1451da177e4SLinus Torvalds #include <linux/netdevice.h>
1461da177e4SLinus Torvalds #include <linux/inet.h>
1471da177e4SLinus Torvalds #include <linux/inetdevice.h>
1481da177e4SLinus Torvalds #include <linux/rtnetlink.h>
1491da177e4SLinus Torvalds #include <linux/if_arp.h>
15034954ddcSFrancesco Fondelli #include <linux/if_vlan.h>
1511da177e4SLinus Torvalds #include <linux/in.h>
1521da177e4SLinus Torvalds #include <linux/ip.h>
1531da177e4SLinus Torvalds #include <linux/ipv6.h>
1541da177e4SLinus Torvalds #include <linux/udp.h>
1551da177e4SLinus Torvalds #include <linux/proc_fs.h>
156d50a6b56SStephen Hemminger #include <linux/seq_file.h>
1571da177e4SLinus Torvalds #include <linux/wait.h>
158f404e9a6SKris Katterjohn #include <linux/etherdevice.h>
159ee74baa7SDavid S. Miller #include <linux/kthread.h>
160268bb0ceSLinus Torvalds #include <linux/prefetch.h>
161457c4cbcSEric W. Biederman #include <net/net_namespace.h>
1621da177e4SLinus Torvalds #include <net/checksum.h>
1631da177e4SLinus Torvalds #include <net/ipv6.h>
164c26bf4a5SThomas Graf #include <net/udp.h>
16573d94e94SStephen Rothwell #include <net/ip6_checksum.h>
1661da177e4SLinus Torvalds #include <net/addrconf.h>
167a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
168a553e4a6SJamal Hadi Salim #include <net/xfrm.h>
169a553e4a6SJamal Hadi Salim #endif
1704e58a027SCong Wang #include <net/netns/generic.h>
1711da177e4SLinus Torvalds #include <asm/byteorder.h>
1721da177e4SLinus Torvalds #include <linux/rcupdate.h>
1731977f032SJiri Slaby #include <linux/bitops.h>
17463adc6fbSStephen Hemminger #include <linux/io.h>
17563adc6fbSStephen Hemminger #include <linux/timex.h>
17663adc6fbSStephen Hemminger #include <linux/uaccess.h>
1771da177e4SLinus Torvalds #include <asm/dma.h>
1781da177e4SLinus Torvalds #include <asm/div64.h>		/* do_div */
1791da177e4SLinus Torvalds 
18040207264SJesper Dangaard Brouer #define VERSION	"2.75"
1811da177e4SLinus Torvalds #define IP_NAME_SZ 32
182ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
183d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100)
1841da177e4SLinus Torvalds 
185f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__);
186f9467eaeSJoe Perches 
187*6f107c74SDmitry Safonov #define PKT_FLAGS							\
188*6f107c74SDmitry Safonov 	pf(IPV6)		/* Interface in IPV6 Mode */		\
189*6f107c74SDmitry Safonov 	pf(IPSRC_RND)		/* IP-Src Random  */			\
190*6f107c74SDmitry Safonov 	pf(IPDST_RND)		/* IP-Dst Random  */			\
191*6f107c74SDmitry Safonov 	pf(TXSIZE_RND)		/* Transmit size is random */		\
192*6f107c74SDmitry Safonov 	pf(UDPSRC_RND)		/* UDP-Src Random */			\
193*6f107c74SDmitry Safonov 	pf(UDPDST_RND)		/* UDP-Dst Random */			\
194*6f107c74SDmitry Safonov 	pf(UDPCSUM)		/* Include UDP checksum */		\
195*6f107c74SDmitry Safonov 	pf(NO_TIMESTAMP)	/* Don't timestamp packets (default TS) */ \
196*6f107c74SDmitry Safonov 	pf(MPLS_RND)		/* Random MPLS labels */		\
197*6f107c74SDmitry Safonov 	pf(QUEUE_MAP_RND)	/* queue map Random */			\
198*6f107c74SDmitry Safonov 	pf(QUEUE_MAP_CPU)	/* queue map mirrors smp_processor_id() */ \
199*6f107c74SDmitry Safonov 	pf(FLOW_SEQ)		/* Sequential flows */			\
200*6f107c74SDmitry Safonov 	pf(IPSEC)		/* ipsec on for flows */		\
201*6f107c74SDmitry Safonov 	pf(MACSRC_RND)		/* MAC-Src Random */			\
202*6f107c74SDmitry Safonov 	pf(MACDST_RND)		/* MAC-Dst Random */			\
203*6f107c74SDmitry Safonov 	pf(VID_RND)		/* Random VLAN ID */			\
204*6f107c74SDmitry Safonov 	pf(SVID_RND)		/* Random SVLAN ID */			\
205*6f107c74SDmitry Safonov 	pf(NODE)		/* Node memory alloc*/			\
206*6f107c74SDmitry Safonov 
207*6f107c74SDmitry Safonov #define pf(flag)		flag##_SHIFT,
208*6f107c74SDmitry Safonov enum pkt_flags {
209*6f107c74SDmitry Safonov 	PKT_FLAGS
210*6f107c74SDmitry Safonov };
211*6f107c74SDmitry Safonov #undef pf
212*6f107c74SDmitry Safonov 
2131da177e4SLinus Torvalds /* Device flag bits */
214*6f107c74SDmitry Safonov #define pf(flag)		static const __u32 F_##flag = (1<<flag##_SHIFT);
215*6f107c74SDmitry Safonov PKT_FLAGS
216*6f107c74SDmitry Safonov #undef pf
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds /* Thread control flag bits */
2196b80d6a6SStephen Hemminger #define T_STOP        (1<<0)	/* Stop run */
2206b80d6a6SStephen Hemminger #define T_RUN         (1<<1)	/* Start run */
2216b80d6a6SStephen Hemminger #define T_REMDEVALL   (1<<2)	/* Remove all devs */
2226b80d6a6SStephen Hemminger #define T_REMDEV      (1<<3)	/* Remove one dev */
2231da177e4SLinus Torvalds 
22462f64aedSAlexei Starovoitov /* Xmit modes */
22562f64aedSAlexei Starovoitov #define M_START_XMIT		0	/* Default normal TX */
22662f64aedSAlexei Starovoitov #define M_NETIF_RECEIVE 	1	/* Inject packets into stack */
2270967f244SJohn Fastabend #define M_QUEUE_XMIT		2	/* Inject packet into qdisc */
22862f64aedSAlexei Starovoitov 
2298788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */
2309a0b1e8bSEric Dumazet #define   if_lock(t)           mutex_lock(&(t->if_lock));
2319a0b1e8bSEric Dumazet #define   if_unlock(t)           mutex_unlock(&(t->if_lock));
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */
2341da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955
235d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen"
236d50a6b56SStephen Hemminger #define PGCTRL	    "pgctrl"
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds #define MAX_CFLOWS  65536
2391da177e4SLinus Torvalds 
24034954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
24134954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
24234954ddcSFrancesco Fondelli 
243222f1806SLuiz Capitulino struct flow_state {
244252e3346SAl Viro 	__be32 cur_daddr;
2451da177e4SLinus Torvalds 	int count;
246a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
247a553e4a6SJamal Hadi Salim 	struct xfrm_state *x;
248a553e4a6SJamal Hadi Salim #endif
249007a531bSJamal Hadi Salim 	__u32 flags;
2501da177e4SLinus Torvalds };
2511da177e4SLinus Torvalds 
252007a531bSJamal Hadi Salim /* flow flag bits */
253007a531bSJamal Hadi Salim #define F_INIT   (1<<0)		/* flow has been initialized */
254007a531bSJamal Hadi Salim 
2551da177e4SLinus Torvalds struct pktgen_dev {
2561da177e4SLinus Torvalds 	/*
2571da177e4SLinus Torvalds 	 * Try to keep frequent/infrequent used vars. separated.
2581da177e4SLinus Torvalds 	 */
25939df232fSStephen Hemminger 	struct proc_dir_entry *entry;	/* proc file */
2601da177e4SLinus Torvalds 	struct pktgen_thread *pg_thread;/* the owner */
26163adc6fbSStephen Hemminger 	struct list_head list;		/* chaining in the thread's run-queue */
2628788370aSJesper Dangaard Brouer 	struct rcu_head	 rcu;		/* freed by RCU */
2631da177e4SLinus Torvalds 
26463adc6fbSStephen Hemminger 	int running;		/* if false, the test will stop */
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	/* If min != max, then we will either do a linear iteration, or
2671da177e4SLinus Torvalds 	 * we will do a random selection from within the range.
2681da177e4SLinus Torvalds 	 */
2691da177e4SLinus Torvalds 	__u32 flags;
27062f64aedSAlexei Starovoitov 	int xmit_mode;
27168bf9f0bSAmerigo Wang 	int min_pkt_size;
27268bf9f0bSAmerigo Wang 	int max_pkt_size;
27316dab72fSJamal Hadi Salim 	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
2741da177e4SLinus Torvalds 	int nfrags;
27562f64aedSAlexei Starovoitov 	int removal_mark;	/* non-zero => the device is marked for
27662f64aedSAlexei Starovoitov 				 * removal by worker thread */
27762f64aedSAlexei Starovoitov 
27826ad7879SEric Dumazet 	struct page *page;
279fd29cf72SStephen Hemminger 	u64 delay;		/* nano-seconds */
280fd29cf72SStephen Hemminger 
2811da177e4SLinus Torvalds 	__u64 count;		/* Default No packets to send */
2821da177e4SLinus Torvalds 	__u64 sofar;		/* How many pkts we've sent so far */
2831da177e4SLinus Torvalds 	__u64 tx_bytes;		/* How many bytes we've transmitted */
284f466dba1SJohn Fastabend 	__u64 errors;		/* Errors when trying to transmit, */
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	/* runtime counters relating to clone_skb */
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	__u32 clone_count;
2891da177e4SLinus Torvalds 	int last_ok;		/* Was last skb sent?
29063adc6fbSStephen Hemminger 				 * Or a failed transmit of some sort?
29163adc6fbSStephen Hemminger 				 * This will keep sequence numbers in order
2921da177e4SLinus Torvalds 				 */
293fd29cf72SStephen Hemminger 	ktime_t next_tx;
294fd29cf72SStephen Hemminger 	ktime_t started_at;
295fd29cf72SStephen Hemminger 	ktime_t stopped_at;
296fd29cf72SStephen Hemminger 	u64	idle_acc;	/* nano-seconds */
297fd29cf72SStephen Hemminger 
2981da177e4SLinus Torvalds 	__u32 seq_num;
2991da177e4SLinus Torvalds 
30063adc6fbSStephen Hemminger 	int clone_skb;		/*
30163adc6fbSStephen Hemminger 				 * Use multiple SKBs during packet gen.
30263adc6fbSStephen Hemminger 				 * If this number is greater than 1, then
30363adc6fbSStephen Hemminger 				 * that many copies of the same packet will be
30463adc6fbSStephen Hemminger 				 * sent before a new packet is allocated.
30563adc6fbSStephen Hemminger 				 * If you want to send 1024 identical packets
30663adc6fbSStephen Hemminger 				 * before creating a new packet,
30763adc6fbSStephen Hemminger 				 * set clone_skb to 1024.
3081da177e4SLinus Torvalds 				 */
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	char dst_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3111da177e4SLinus Torvalds 	char dst_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3121da177e4SLinus Torvalds 	char src_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3131da177e4SLinus Torvalds 	char src_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	struct in6_addr in6_saddr;
3161da177e4SLinus Torvalds 	struct in6_addr in6_daddr;
3171da177e4SLinus Torvalds 	struct in6_addr cur_in6_daddr;
3181da177e4SLinus Torvalds 	struct in6_addr cur_in6_saddr;
3191da177e4SLinus Torvalds 	/* For ranges */
3201da177e4SLinus Torvalds 	struct in6_addr min_in6_daddr;
3211da177e4SLinus Torvalds 	struct in6_addr max_in6_daddr;
3221da177e4SLinus Torvalds 	struct in6_addr min_in6_saddr;
3231da177e4SLinus Torvalds 	struct in6_addr max_in6_saddr;
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	/* If we're doing ranges, random or incremental, then this
3261da177e4SLinus Torvalds 	 * defines the min/max for those ranges.
3271da177e4SLinus Torvalds 	 */
328252e3346SAl Viro 	__be32 saddr_min;	/* inclusive, source IP address */
329252e3346SAl Viro 	__be32 saddr_max;	/* exclusive, source IP address */
330252e3346SAl Viro 	__be32 daddr_min;	/* inclusive, dest IP address */
331252e3346SAl Viro 	__be32 daddr_max;	/* exclusive, dest IP address */
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	__u16 udp_src_min;	/* inclusive, source UDP port */
3341da177e4SLinus Torvalds 	__u16 udp_src_max;	/* exclusive, source UDP port */
3351da177e4SLinus Torvalds 	__u16 udp_dst_min;	/* inclusive, dest UDP port */
3361da177e4SLinus Torvalds 	__u16 udp_dst_max;	/* exclusive, dest UDP port */
3371da177e4SLinus Torvalds 
3381ca7768cSFrancesco Fondelli 	/* DSCP + ECN */
33963adc6fbSStephen Hemminger 	__u8 tos;            /* six MSB of (former) IPv4 TOS
34063adc6fbSStephen Hemminger 				are for dscp codepoint */
34163adc6fbSStephen Hemminger 	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6
34263adc6fbSStephen Hemminger 				(see RFC 3260, sec. 4) */
3431ca7768cSFrancesco Fondelli 
344ca6549afSSteven Whitehouse 	/* MPLS */
34595c96174SEric Dumazet 	unsigned int nr_labels;	/* Depth of stack, 0 = no MPLS */
346ca6549afSSteven Whitehouse 	__be32 labels[MAX_MPLS_LABELS];
347ca6549afSSteven Whitehouse 
34834954ddcSFrancesco Fondelli 	/* VLAN/SVLAN (802.1Q/Q-in-Q) */
34934954ddcSFrancesco Fondelli 	__u8  vlan_p;
35034954ddcSFrancesco Fondelli 	__u8  vlan_cfi;
35134954ddcSFrancesco Fondelli 	__u16 vlan_id;  /* 0xffff means no vlan tag */
35234954ddcSFrancesco Fondelli 
35334954ddcSFrancesco Fondelli 	__u8  svlan_p;
35434954ddcSFrancesco Fondelli 	__u8  svlan_cfi;
35534954ddcSFrancesco Fondelli 	__u16 svlan_id; /* 0xffff means no svlan tag */
35634954ddcSFrancesco Fondelli 
3571da177e4SLinus Torvalds 	__u32 src_mac_count;	/* How many MACs to iterate through */
3581da177e4SLinus Torvalds 	__u32 dst_mac_count;	/* How many MACs to iterate through */
3591da177e4SLinus Torvalds 
360f404e9a6SKris Katterjohn 	unsigned char dst_mac[ETH_ALEN];
361f404e9a6SKris Katterjohn 	unsigned char src_mac[ETH_ALEN];
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	__u32 cur_dst_mac_offset;
3641da177e4SLinus Torvalds 	__u32 cur_src_mac_offset;
365252e3346SAl Viro 	__be32 cur_saddr;
366252e3346SAl Viro 	__be32 cur_daddr;
36766ed1e5eSEric Dumazet 	__u16 ip_id;
3681da177e4SLinus Torvalds 	__u16 cur_udp_dst;
3691da177e4SLinus Torvalds 	__u16 cur_udp_src;
37045b270f8SRobert Olsson 	__u16 cur_queue_map;
3711da177e4SLinus Torvalds 	__u32 cur_pkt_size;
372baac8564SEric Dumazet 	__u32 last_pkt_size;
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	__u8 hh[14];
3751da177e4SLinus Torvalds 	/* = {
3761da177e4SLinus Torvalds 	   0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	   We fill in SRC address later
3791da177e4SLinus Torvalds 	   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801da177e4SLinus Torvalds 	   0x08, 0x00
3811da177e4SLinus Torvalds 	   };
3821da177e4SLinus Torvalds 	 */
3831da177e4SLinus Torvalds 	__u16 pad;		/* pad out the hh struct to an even 16 bytes */
3841da177e4SLinus Torvalds 
38563adc6fbSStephen Hemminger 	struct sk_buff *skb;	/* skb we are to transmit next, used for when we
3861da177e4SLinus Torvalds 				 * are transmitting the same one multiple times
3871da177e4SLinus Torvalds 				 */
38863adc6fbSStephen Hemminger 	struct net_device *odev; /* The out-going device.
38963adc6fbSStephen Hemminger 				  * Note that the device should have it's
39063adc6fbSStephen Hemminger 				  * pg_info pointer pointing back to this
39163adc6fbSStephen Hemminger 				  * device.
39263adc6fbSStephen Hemminger 				  * Set when the user specifies the out-going
39363adc6fbSStephen Hemminger 				  * device name (not when the inject is
3941da177e4SLinus Torvalds 				  * started as it used to do.)
3951da177e4SLinus Torvalds 				  */
396593f63b0SEric Dumazet 	char odevname[32];
3971da177e4SLinus Torvalds 	struct flow_state *flows;
39895c96174SEric Dumazet 	unsigned int cflows;	/* Concurrent flows (config) */
39995c96174SEric Dumazet 	unsigned int lflow;		/* Flow length  (config) */
40095c96174SEric Dumazet 	unsigned int nflows;	/* accumulated flows (stats) */
40195c96174SEric Dumazet 	unsigned int curfl;		/* current sequenced flow (state)*/
40245b270f8SRobert Olsson 
40345b270f8SRobert Olsson 	u16 queue_map_min;
40445b270f8SRobert Olsson 	u16 queue_map_max;
4059e50e3acSJohn Fastabend 	__u32 skb_priority;	/* skb priority field */
40638b2cf29SAlexei Starovoitov 	unsigned int burst;	/* number of duplicated packets to burst */
407e99b99b4SRobert Olsson 	int node;               /* Memory node */
40845b270f8SRobert Olsson 
409a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
410a553e4a6SJamal Hadi Salim 	__u8	ipsmode;		/* IPSEC mode (config) */
411a553e4a6SJamal Hadi Salim 	__u8	ipsproto;		/* IPSEC type (config) */
412de4aee7dSFan Du 	__u32	spi;
413b6ca8bd5SDavid Miller 	struct xfrm_dst xdst;
414cf93d47eSFan Du 	struct dst_ops dstops;
415a553e4a6SJamal Hadi Salim #endif
41639df232fSStephen Hemminger 	char result[512];
4171da177e4SLinus Torvalds };
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds struct pktgen_hdr {
420252e3346SAl Viro 	__be32 pgh_magic;
421252e3346SAl Viro 	__be32 seq_num;
422252e3346SAl Viro 	__be32 tv_sec;
423252e3346SAl Viro 	__be32 tv_usec;
4241da177e4SLinus Torvalds };
4251da177e4SLinus Torvalds 
4264e58a027SCong Wang 
427c7d03a00SAlexey Dobriyan static unsigned int pg_net_id __read_mostly;
4284e58a027SCong Wang 
4294e58a027SCong Wang struct pktgen_net {
4304e58a027SCong Wang 	struct net		*net;
4314e58a027SCong Wang 	struct proc_dir_entry	*proc_dir;
4324e58a027SCong Wang 	struct list_head	pktgen_threads;
4334e58a027SCong Wang 	bool			pktgen_exiting;
4344e58a027SCong Wang };
435551eaff1SEric Dumazet 
4361da177e4SLinus Torvalds struct pktgen_thread {
4379a0b1e8bSEric Dumazet 	struct mutex if_lock;		/* for list of devices */
438c26a8016SLuiz Capitulino 	struct list_head if_list;	/* All device here */
439cdcdbe0bSLuiz Capitulino 	struct list_head th_list;
440ee74baa7SDavid S. Miller 	struct task_struct *tsk;
4411da177e4SLinus Torvalds 	char result[512];
4421da177e4SLinus Torvalds 
44363adc6fbSStephen Hemminger 	/* Field for thread to receive "posted" events terminate,
44463adc6fbSStephen Hemminger 	   stop ifs etc. */
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds 	u32 control;
4471da177e4SLinus Torvalds 	int cpu;
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 	wait_queue_head_t queue;
450d3ede327SDenis V. Lunev 	struct completion start_done;
4514e58a027SCong Wang 	struct pktgen_net *net;
4521da177e4SLinus Torvalds };
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds #define REMOVE 1
4551da177e4SLinus Torvalds #define FIND   0
4561da177e4SLinus Torvalds 
457c3d2f52dSStephen Hemminger static const char version[] =
458f9467eaeSJoe Perches 	"Packet Generator for packet performance testing. "
459f9467eaeSJoe Perches 	"Version: " VERSION "\n";
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
4621da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
463222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
4643e984840SEric Dumazet 					  const char *ifname, bool exact);
4651da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
4664e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn);
4674e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn);
4684e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn);
4693bda06a3SStephen Hemminger 
4701da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t);
4711da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
47239df232fSStephen Hemminger 
4731da177e4SLinus Torvalds /* Module parameters, defaults. */
47465c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000;
47565c5b786SStephen Hemminger static int pg_delay_d __read_mostly;
47665c5b786SStephen Hemminger static int pg_clone_skb_d  __read_mostly;
47765c5b786SStephen Hemminger static int debug  __read_mostly;
4781da177e4SLinus Torvalds 
479222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock);
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = {
4821da177e4SLinus Torvalds 	.notifier_call = pktgen_device_event,
4831da177e4SLinus Torvalds };
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds /*
4861da177e4SLinus Torvalds  * /proc handling functions
4871da177e4SLinus Torvalds  *
4881da177e4SLinus Torvalds  */
4891da177e4SLinus Torvalds 
490d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v)
491d50a6b56SStephen Hemminger {
492c3d2f52dSStephen Hemminger 	seq_puts(seq, version);
493d50a6b56SStephen Hemminger 	return 0;
494d50a6b56SStephen Hemminger }
4951da177e4SLinus Torvalds 
496d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf,
4971da177e4SLinus Torvalds 			    size_t count, loff_t *ppos)
4981da177e4SLinus Torvalds {
499d50a6b56SStephen Hemminger 	char data[128];
5004e58a027SCong Wang 	struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
5011da177e4SLinus Torvalds 
50209455747SMathias Krause 	if (!capable(CAP_NET_ADMIN))
50309455747SMathias Krause 		return -EPERM;
5041da177e4SLinus Torvalds 
50520b0c718SMathias Krause 	if (count == 0)
50620b0c718SMathias Krause 		return -EINVAL;
50720b0c718SMathias Krause 
508d50a6b56SStephen Hemminger 	if (count > sizeof(data))
509d50a6b56SStephen Hemminger 		count = sizeof(data);
5101da177e4SLinus Torvalds 
51109455747SMathias Krause 	if (copy_from_user(data, buf, count))
51209455747SMathias Krause 		return -EFAULT;
51309455747SMathias Krause 
51420b0c718SMathias Krause 	data[count - 1] = 0;	/* Strip trailing '\n' and terminate string */
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 	if (!strcmp(data, "stop"))
5174e58a027SCong Wang 		pktgen_stop_all_threads_ifs(pn);
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	else if (!strcmp(data, "start"))
5204e58a027SCong Wang 		pktgen_run_all_threads(pn);
5211da177e4SLinus Torvalds 
522eb37b41cSJesse Brandeburg 	else if (!strcmp(data, "reset"))
5234e58a027SCong Wang 		pktgen_reset_all_threads(pn);
524eb37b41cSJesse Brandeburg 
5251da177e4SLinus Torvalds 	else
52640207264SJesper Dangaard Brouer 		return -EINVAL;
5271da177e4SLinus Torvalds 
52809455747SMathias Krause 	return count;
5291da177e4SLinus Torvalds }
5301da177e4SLinus Torvalds 
531d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file)
5321da177e4SLinus Torvalds {
533d9dda78bSAl Viro 	return single_open(file, pgctrl_show, PDE_DATA(inode));
534d50a6b56SStephen Hemminger }
535d50a6b56SStephen Hemminger 
5369a32144eSArjan van de Ven static const struct file_operations pktgen_fops = {
537d50a6b56SStephen Hemminger 	.open    = pgctrl_open,
538d50a6b56SStephen Hemminger 	.read    = seq_read,
539d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
540d50a6b56SStephen Hemminger 	.write   = pgctrl_write,
541d50a6b56SStephen Hemminger 	.release = single_release,
542d50a6b56SStephen Hemminger };
543d50a6b56SStephen Hemminger 
544d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v)
545d50a6b56SStephen Hemminger {
546648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev = seq->private;
547fd29cf72SStephen Hemminger 	ktime_t stopped;
548fd29cf72SStephen Hemminger 	u64 idle;
5491da177e4SLinus Torvalds 
550222f1806SLuiz Capitulino 	seq_printf(seq,
551222f1806SLuiz Capitulino 		   "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
552222f1806SLuiz Capitulino 		   (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size,
553222f1806SLuiz Capitulino 		   pkt_dev->max_pkt_size);
5541da177e4SLinus Torvalds 
555222f1806SLuiz Capitulino 	seq_printf(seq,
556fd29cf72SStephen Hemminger 		   "     frags: %d  delay: %llu  clone_skb: %d  ifname: %s\n",
557fd29cf72SStephen Hemminger 		   pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
558593f63b0SEric Dumazet 		   pkt_dev->clone_skb, pkt_dev->odevname);
5591da177e4SLinus Torvalds 
560222f1806SLuiz Capitulino 	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
561222f1806SLuiz Capitulino 		   pkt_dev->lflow);
5621da177e4SLinus Torvalds 
56345b270f8SRobert Olsson 	seq_printf(seq,
56445b270f8SRobert Olsson 		   "     queue_map_min: %u  queue_map_max: %u\n",
56545b270f8SRobert Olsson 		   pkt_dev->queue_map_min,
56645b270f8SRobert Olsson 		   pkt_dev->queue_map_max);
56745b270f8SRobert Olsson 
5689e50e3acSJohn Fastabend 	if (pkt_dev->skb_priority)
5699e50e3acSJohn Fastabend 		seq_printf(seq, "     skb_priority: %u\n",
5709e50e3acSJohn Fastabend 			   pkt_dev->skb_priority);
5719e50e3acSJohn Fastabend 
5721da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
573222f1806SLuiz Capitulino 		seq_printf(seq,
57447a0200dSAlexey Dobriyan 			   "     saddr: %pI6c  min_saddr: %pI6c  max_saddr: %pI6c\n"
57547a0200dSAlexey Dobriyan 			   "     daddr: %pI6c  min_daddr: %pI6c  max_daddr: %pI6c\n",
57647a0200dSAlexey Dobriyan 			   &pkt_dev->in6_saddr,
57747a0200dSAlexey Dobriyan 			   &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr,
57847a0200dSAlexey Dobriyan 			   &pkt_dev->in6_daddr,
57947a0200dSAlexey Dobriyan 			   &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr);
58063adc6fbSStephen Hemminger 	} else {
581222f1806SLuiz Capitulino 		seq_printf(seq,
58263adc6fbSStephen Hemminger 			   "     dst_min: %s  dst_max: %s\n",
58363adc6fbSStephen Hemminger 			   pkt_dev->dst_min, pkt_dev->dst_max);
58463adc6fbSStephen Hemminger 		seq_printf(seq,
58563adc6fbSStephen Hemminger 			   "     src_min: %s  src_max: %s\n",
58663adc6fbSStephen Hemminger 			   pkt_dev->src_min, pkt_dev->src_max);
58763adc6fbSStephen Hemminger 	}
5881da177e4SLinus Torvalds 
589d50a6b56SStephen Hemminger 	seq_puts(seq, "     src_mac: ");
5901da177e4SLinus Torvalds 
591e174961cSJohannes Berg 	seq_printf(seq, "%pM ",
592e174961cSJohannes Berg 		   is_zero_ether_addr(pkt_dev->src_mac) ?
593e174961cSJohannes Berg 			     pkt_dev->odev->dev_addr : pkt_dev->src_mac);
5941da177e4SLinus Torvalds 
59597dc48e2SThomas Graf 	seq_puts(seq, "dst_mac: ");
596e174961cSJohannes Berg 	seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
5971da177e4SLinus Torvalds 
598222f1806SLuiz Capitulino 	seq_printf(seq,
59963adc6fbSStephen Hemminger 		   "     udp_src_min: %d  udp_src_max: %d"
60063adc6fbSStephen Hemminger 		   "  udp_dst_min: %d  udp_dst_max: %d\n",
601222f1806SLuiz Capitulino 		   pkt_dev->udp_src_min, pkt_dev->udp_src_max,
602222f1806SLuiz Capitulino 		   pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);
6031da177e4SLinus Torvalds 
604222f1806SLuiz Capitulino 	seq_printf(seq,
605ca6549afSSteven Whitehouse 		   "     src_mac_count: %d  dst_mac_count: %d\n",
6061da177e4SLinus Torvalds 		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
6071da177e4SLinus Torvalds 
608ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels) {
60995c96174SEric Dumazet 		unsigned int i;
61097dc48e2SThomas Graf 		seq_puts(seq, "     mpls: ");
611ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
612ca6549afSSteven Whitehouse 			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
613ca6549afSSteven Whitehouse 				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
614ca6549afSSteven Whitehouse 	}
615ca6549afSSteven Whitehouse 
61663adc6fbSStephen Hemminger 	if (pkt_dev->vlan_id != 0xffff)
61734954ddcSFrancesco Fondelli 		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
61863adc6fbSStephen Hemminger 			   pkt_dev->vlan_id, pkt_dev->vlan_p,
61963adc6fbSStephen Hemminger 			   pkt_dev->vlan_cfi);
62034954ddcSFrancesco Fondelli 
62163adc6fbSStephen Hemminger 	if (pkt_dev->svlan_id != 0xffff)
62234954ddcSFrancesco Fondelli 		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
62363adc6fbSStephen Hemminger 			   pkt_dev->svlan_id, pkt_dev->svlan_p,
62463adc6fbSStephen Hemminger 			   pkt_dev->svlan_cfi);
62534954ddcSFrancesco Fondelli 
62663adc6fbSStephen Hemminger 	if (pkt_dev->tos)
6271ca7768cSFrancesco Fondelli 		seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);
6281ca7768cSFrancesco Fondelli 
62963adc6fbSStephen Hemminger 	if (pkt_dev->traffic_class)
6301ca7768cSFrancesco Fondelli 		seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
6311ca7768cSFrancesco Fondelli 
63238b2cf29SAlexei Starovoitov 	if (pkt_dev->burst > 1)
63338b2cf29SAlexei Starovoitov 		seq_printf(seq, "     burst: %d\n", pkt_dev->burst);
63438b2cf29SAlexei Starovoitov 
635e99b99b4SRobert Olsson 	if (pkt_dev->node >= 0)
636e99b99b4SRobert Olsson 		seq_printf(seq, "     node: %d\n", pkt_dev->node);
637e99b99b4SRobert Olsson 
63862f64aedSAlexei Starovoitov 	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
63962f64aedSAlexei Starovoitov 		seq_puts(seq, "     xmit_mode: netif_receive\n");
6400967f244SJohn Fastabend 	else if (pkt_dev->xmit_mode == M_QUEUE_XMIT)
6410967f244SJohn Fastabend 		seq_puts(seq, "     xmit_mode: xmit_queue\n");
64262f64aedSAlexei Starovoitov 
64397dc48e2SThomas Graf 	seq_puts(seq, "     Flags: ");
644ca6549afSSteven Whitehouse 
6451da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
64697dc48e2SThomas Graf 		seq_puts(seq, "IPV6  ");
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPSRC_RND)
64997dc48e2SThomas Graf 		seq_puts(seq, "IPSRC_RND  ");
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPDST_RND)
65297dc48e2SThomas Graf 		seq_puts(seq, "IPDST_RND  ");
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds 	if (pkt_dev->flags & F_TXSIZE_RND)
65597dc48e2SThomas Graf 		seq_puts(seq, "TXSIZE_RND  ");
6561da177e4SLinus Torvalds 
6571da177e4SLinus Torvalds 	if (pkt_dev->flags & F_UDPSRC_RND)
65897dc48e2SThomas Graf 		seq_puts(seq, "UDPSRC_RND  ");
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	if (pkt_dev->flags & F_UDPDST_RND)
66197dc48e2SThomas Graf 		seq_puts(seq, "UDPDST_RND  ");
6621da177e4SLinus Torvalds 
663c26bf4a5SThomas Graf 	if (pkt_dev->flags & F_UDPCSUM)
66497dc48e2SThomas Graf 		seq_puts(seq, "UDPCSUM  ");
665c26bf4a5SThomas Graf 
666afb84b62SJesper Dangaard Brouer 	if (pkt_dev->flags & F_NO_TIMESTAMP)
667afb84b62SJesper Dangaard Brouer 		seq_puts(seq, "NO_TIMESTAMP  ");
668afb84b62SJesper Dangaard Brouer 
669ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND)
67097dc48e2SThomas Graf 		seq_puts(seq,  "MPLS_RND  ");
671ca6549afSSteven Whitehouse 
67245b270f8SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_RND)
67397dc48e2SThomas Graf 		seq_puts(seq,  "QUEUE_MAP_RND  ");
67445b270f8SRobert Olsson 
675e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
67697dc48e2SThomas Graf 		seq_puts(seq,  "QUEUE_MAP_CPU  ");
677e6fce5b9SRobert Olsson 
678007a531bSJamal Hadi Salim 	if (pkt_dev->cflows) {
679007a531bSJamal Hadi Salim 		if (pkt_dev->flags & F_FLOW_SEQ)
68097dc48e2SThomas Graf 			seq_puts(seq,  "FLOW_SEQ  "); /*in sequence flows*/
681007a531bSJamal Hadi Salim 		else
68297dc48e2SThomas Graf 			seq_puts(seq,  "FLOW_RND  ");
683007a531bSJamal Hadi Salim 	}
684007a531bSJamal Hadi Salim 
685a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
686*6f107c74SDmitry Safonov 	if (pkt_dev->flags & F_IPSEC) {
68797dc48e2SThomas Graf 		seq_puts(seq,  "IPSEC  ");
6888101328bSFan Du 		if (pkt_dev->spi)
6898101328bSFan Du 			seq_printf(seq, "spi:%u", pkt_dev->spi);
6908101328bSFan Du 	}
691a553e4a6SJamal Hadi Salim #endif
692a553e4a6SJamal Hadi Salim 
6931da177e4SLinus Torvalds 	if (pkt_dev->flags & F_MACSRC_RND)
69497dc48e2SThomas Graf 		seq_puts(seq, "MACSRC_RND  ");
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	if (pkt_dev->flags & F_MACDST_RND)
69797dc48e2SThomas Graf 		seq_puts(seq, "MACDST_RND  ");
6981da177e4SLinus Torvalds 
69934954ddcSFrancesco Fondelli 	if (pkt_dev->flags & F_VID_RND)
70097dc48e2SThomas Graf 		seq_puts(seq, "VID_RND  ");
70134954ddcSFrancesco Fondelli 
70234954ddcSFrancesco Fondelli 	if (pkt_dev->flags & F_SVID_RND)
70397dc48e2SThomas Graf 		seq_puts(seq, "SVID_RND  ");
70434954ddcSFrancesco Fondelli 
705e99b99b4SRobert Olsson 	if (pkt_dev->flags & F_NODE)
70697dc48e2SThomas Graf 		seq_puts(seq, "NODE_ALLOC  ");
707e99b99b4SRobert Olsson 
708d50a6b56SStephen Hemminger 	seq_puts(seq, "\n");
7091da177e4SLinus Torvalds 
710fd29cf72SStephen Hemminger 	/* not really stopped, more like last-running-at */
711398f382cSDaniel Borkmann 	stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at;
712fd29cf72SStephen Hemminger 	idle = pkt_dev->idle_acc;
713fd29cf72SStephen Hemminger 	do_div(idle, NSEC_PER_USEC);
7141da177e4SLinus Torvalds 
715222f1806SLuiz Capitulino 	seq_printf(seq,
716fd29cf72SStephen Hemminger 		   "Current:\n     pkts-sofar: %llu  errors: %llu\n",
7171da177e4SLinus Torvalds 		   (unsigned long long)pkt_dev->sofar,
718fd29cf72SStephen Hemminger 		   (unsigned long long)pkt_dev->errors);
719fd29cf72SStephen Hemminger 
720fd29cf72SStephen Hemminger 	seq_printf(seq,
721fd29cf72SStephen Hemminger 		   "     started: %lluus  stopped: %lluus idle: %lluus\n",
722fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(pkt_dev->started_at),
723fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(stopped),
724fd29cf72SStephen Hemminger 		   (unsigned long long) idle);
7251da177e4SLinus Torvalds 
726222f1806SLuiz Capitulino 	seq_printf(seq,
727222f1806SLuiz Capitulino 		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
728d50a6b56SStephen Hemminger 		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
729d50a6b56SStephen Hemminger 		   pkt_dev->cur_src_mac_offset);
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
73247a0200dSAlexey Dobriyan 		seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
73347a0200dSAlexey Dobriyan 				&pkt_dev->cur_in6_saddr,
73447a0200dSAlexey Dobriyan 				&pkt_dev->cur_in6_daddr);
735222f1806SLuiz Capitulino 	} else
7360373a946SAmerigo Wang 		seq_printf(seq, "     cur_saddr: %pI4  cur_daddr: %pI4\n",
7370373a946SAmerigo Wang 			   &pkt_dev->cur_saddr, &pkt_dev->cur_daddr);
7381da177e4SLinus Torvalds 
739d50a6b56SStephen Hemminger 	seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
7401da177e4SLinus Torvalds 		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
7411da177e4SLinus Torvalds 
74245b270f8SRobert Olsson 	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);
74345b270f8SRobert Olsson 
744d50a6b56SStephen Hemminger 	seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	if (pkt_dev->result[0])
747d50a6b56SStephen Hemminger 		seq_printf(seq, "Result: %s\n", pkt_dev->result);
7481da177e4SLinus Torvalds 	else
74997dc48e2SThomas Graf 		seq_puts(seq, "Result: Idle\n");
7501da177e4SLinus Torvalds 
751d50a6b56SStephen Hemminger 	return 0;
7521da177e4SLinus Torvalds }
7531da177e4SLinus Torvalds 
754ca6549afSSteven Whitehouse 
75563adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
75663adc6fbSStephen Hemminger 		     __u32 *num)
757ca6549afSSteven Whitehouse {
758ca6549afSSteven Whitehouse 	int i = 0;
759ca6549afSSteven Whitehouse 	*num = 0;
760ca6549afSSteven Whitehouse 
7611ca7768cSFrancesco Fondelli 	for (; i < maxlen; i++) {
76282fd5b5dSAndy Shevchenko 		int value;
763ca6549afSSteven Whitehouse 		char c;
764ca6549afSSteven Whitehouse 		*num <<= 4;
765ca6549afSSteven Whitehouse 		if (get_user(c, &user_buffer[i]))
766ca6549afSSteven Whitehouse 			return -EFAULT;
76782fd5b5dSAndy Shevchenko 		value = hex_to_bin(c);
76882fd5b5dSAndy Shevchenko 		if (value >= 0)
76982fd5b5dSAndy Shevchenko 			*num |= value;
770ca6549afSSteven Whitehouse 		else
771ca6549afSSteven Whitehouse 			break;
772ca6549afSSteven Whitehouse 	}
773ca6549afSSteven Whitehouse 	return i;
774ca6549afSSteven Whitehouse }
775ca6549afSSteven Whitehouse 
776222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer,
777222f1806SLuiz Capitulino 			     unsigned int maxlen)
7781da177e4SLinus Torvalds {
7791da177e4SLinus Torvalds 	int i;
7801da177e4SLinus Torvalds 
7811da177e4SLinus Torvalds 	for (i = 0; i < maxlen; i++) {
7821da177e4SLinus Torvalds 		char c;
7831da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7841da177e4SLinus Torvalds 			return -EFAULT;
7851da177e4SLinus Torvalds 		switch (c) {
7861da177e4SLinus Torvalds 		case '\"':
7871da177e4SLinus Torvalds 		case '\n':
7881da177e4SLinus Torvalds 		case '\r':
7891da177e4SLinus Torvalds 		case '\t':
7901da177e4SLinus Torvalds 		case ' ':
7911da177e4SLinus Torvalds 		case '=':
7921da177e4SLinus Torvalds 			break;
7931da177e4SLinus Torvalds 		default:
7941da177e4SLinus Torvalds 			goto done;
7953ff50b79SStephen Hemminger 		}
7961da177e4SLinus Torvalds 	}
7971da177e4SLinus Torvalds done:
7981da177e4SLinus Torvalds 	return i;
7991da177e4SLinus Torvalds }
8001da177e4SLinus Torvalds 
801bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen,
802bf0813bdSPaul Gortmaker 				unsigned long *num)
8031da177e4SLinus Torvalds {
804d6182223SPaul Gortmaker 	int i;
8051da177e4SLinus Torvalds 	*num = 0;
8061da177e4SLinus Torvalds 
807d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
8081da177e4SLinus Torvalds 		char c;
8091da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
8101da177e4SLinus Torvalds 			return -EFAULT;
8111da177e4SLinus Torvalds 		if ((c >= '0') && (c <= '9')) {
8121da177e4SLinus Torvalds 			*num *= 10;
8131da177e4SLinus Torvalds 			*num += c - '0';
8141da177e4SLinus Torvalds 		} else
8151da177e4SLinus Torvalds 			break;
8161da177e4SLinus Torvalds 	}
8171da177e4SLinus Torvalds 	return i;
8181da177e4SLinus Torvalds }
8191da177e4SLinus Torvalds 
8201da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen)
8211da177e4SLinus Torvalds {
822d6182223SPaul Gortmaker 	int i;
8231da177e4SLinus Torvalds 
824d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
8251da177e4SLinus Torvalds 		char c;
8261da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
8271da177e4SLinus Torvalds 			return -EFAULT;
8281da177e4SLinus Torvalds 		switch (c) {
8291da177e4SLinus Torvalds 		case '\"':
8301da177e4SLinus Torvalds 		case '\n':
8311da177e4SLinus Torvalds 		case '\r':
8321da177e4SLinus Torvalds 		case '\t':
8331da177e4SLinus Torvalds 		case ' ':
8341da177e4SLinus Torvalds 			goto done_str;
8351da177e4SLinus Torvalds 		default:
8361da177e4SLinus Torvalds 			break;
8373ff50b79SStephen Hemminger 		}
8381da177e4SLinus Torvalds 	}
8391da177e4SLinus Torvalds done_str:
8401da177e4SLinus Torvalds 	return i;
8411da177e4SLinus Torvalds }
8421da177e4SLinus Torvalds 
843ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
844ca6549afSSteven Whitehouse {
84595c96174SEric Dumazet 	unsigned int n = 0;
846ca6549afSSteven Whitehouse 	char c;
847ca6549afSSteven Whitehouse 	ssize_t i = 0;
848ca6549afSSteven Whitehouse 	int len;
849ca6549afSSteven Whitehouse 
850ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = 0;
851ca6549afSSteven Whitehouse 	do {
852ca6549afSSteven Whitehouse 		__u32 tmp;
8531ca7768cSFrancesco Fondelli 		len = hex32_arg(&buffer[i], 8, &tmp);
854ca6549afSSteven Whitehouse 		if (len <= 0)
855ca6549afSSteven Whitehouse 			return len;
856ca6549afSSteven Whitehouse 		pkt_dev->labels[n] = htonl(tmp);
857ca6549afSSteven Whitehouse 		if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
858ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
859ca6549afSSteven Whitehouse 		i += len;
860ca6549afSSteven Whitehouse 		if (get_user(c, &buffer[i]))
861ca6549afSSteven Whitehouse 			return -EFAULT;
862ca6549afSSteven Whitehouse 		i++;
863ca6549afSSteven Whitehouse 		n++;
864ca6549afSSteven Whitehouse 		if (n >= MAX_MPLS_LABELS)
865ca6549afSSteven Whitehouse 			return -E2BIG;
866ca6549afSSteven Whitehouse 	} while (c == ',');
867ca6549afSSteven Whitehouse 
868ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = n;
869ca6549afSSteven Whitehouse 	return i;
870ca6549afSSteven Whitehouse }
871ca6549afSSteven Whitehouse 
872222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file,
873222f1806SLuiz Capitulino 			       const char __user * user_buffer, size_t count,
874222f1806SLuiz Capitulino 			       loff_t * offset)
8751da177e4SLinus Torvalds {
8768a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
877d50a6b56SStephen Hemminger 	struct pktgen_dev *pkt_dev = seq->private;
878d6182223SPaul Gortmaker 	int i, max, len;
8791da177e4SLinus Torvalds 	char name[16], valstr[32];
8801da177e4SLinus Torvalds 	unsigned long value = 0;
8811da177e4SLinus Torvalds 	char *pg_result = NULL;
8821da177e4SLinus Torvalds 	int tmp = 0;
8831da177e4SLinus Torvalds 	char buf[128];
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds 	pg_result = &(pkt_dev->result[0]);
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	if (count < 1) {
888294a0b7fSJoe Perches 		pr_warn("wrong command format\n");
8891da177e4SLinus Torvalds 		return -EINVAL;
8901da177e4SLinus Torvalds 	}
8911da177e4SLinus Torvalds 
892d6182223SPaul Gortmaker 	max = count;
893d6182223SPaul Gortmaker 	tmp = count_trail_chars(user_buffer, max);
8941da177e4SLinus Torvalds 	if (tmp < 0) {
895294a0b7fSJoe Perches 		pr_warn("illegal format\n");
8961da177e4SLinus Torvalds 		return tmp;
8971da177e4SLinus Torvalds 	}
898d6182223SPaul Gortmaker 	i = tmp;
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds 	/* Read variable name */
9011da177e4SLinus Torvalds 
9021da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
90363adc6fbSStephen Hemminger 	if (len < 0)
904222f1806SLuiz Capitulino 		return len;
90563adc6fbSStephen Hemminger 
9061da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
9071da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
9081da177e4SLinus Torvalds 		return -EFAULT;
9091da177e4SLinus Torvalds 	i += len;
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds 	max = count - i;
9121da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
9131da177e4SLinus Torvalds 	if (len < 0)
9141da177e4SLinus Torvalds 		return len;
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds 	i += len;
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds 	if (debug) {
91986c2c0a8SDmitry Torokhov 		size_t copy = min_t(size_t, count, 1023);
920448d7b5dSNelson Elhage 		char tb[copy + 1];
921448d7b5dSNelson Elhage 		if (copy_from_user(tb, user_buffer, copy))
9221da177e4SLinus Torvalds 			return -EFAULT;
923448d7b5dSNelson Elhage 		tb[copy] = 0;
924f342cda7SJoe Perches 		pr_debug("%s,%lu  buffer -:%s:-\n",
925f342cda7SJoe Perches 			 name, (unsigned long)count, tb);
9261da177e4SLinus Torvalds 	}
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds 	if (!strcmp(name, "min_pkt_size")) {
9291da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
93063adc6fbSStephen Hemminger 		if (len < 0)
931222f1806SLuiz Capitulino 			return len;
93263adc6fbSStephen Hemminger 
9331da177e4SLinus Torvalds 		i += len;
9341da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9351da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9361da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9371da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9381da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9391da177e4SLinus Torvalds 		}
940222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: min_pkt_size=%u",
941222f1806SLuiz Capitulino 			pkt_dev->min_pkt_size);
9421da177e4SLinus Torvalds 		return count;
9431da177e4SLinus Torvalds 	}
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 	if (!strcmp(name, "max_pkt_size")) {
9461da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
94763adc6fbSStephen Hemminger 		if (len < 0)
948222f1806SLuiz Capitulino 			return len;
94963adc6fbSStephen Hemminger 
9501da177e4SLinus Torvalds 		i += len;
9511da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9521da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9531da177e4SLinus Torvalds 		if (value != pkt_dev->max_pkt_size) {
9541da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9551da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9561da177e4SLinus Torvalds 		}
957222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: max_pkt_size=%u",
958222f1806SLuiz Capitulino 			pkt_dev->max_pkt_size);
9591da177e4SLinus Torvalds 		return count;
9601da177e4SLinus Torvalds 	}
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds 	/* Shortcut for min = max */
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 	if (!strcmp(name, "pkt_size")) {
9651da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
96663adc6fbSStephen Hemminger 		if (len < 0)
967222f1806SLuiz Capitulino 			return len;
96863adc6fbSStephen Hemminger 
9691da177e4SLinus Torvalds 		i += len;
9701da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9711da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9721da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9731da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9741da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9751da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9761da177e4SLinus Torvalds 		}
9771da177e4SLinus Torvalds 		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
9781da177e4SLinus Torvalds 		return count;
9791da177e4SLinus Torvalds 	}
9801da177e4SLinus Torvalds 
9811da177e4SLinus Torvalds 	if (!strcmp(name, "debug")) {
9821da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
98363adc6fbSStephen Hemminger 		if (len < 0)
984222f1806SLuiz Capitulino 			return len;
98563adc6fbSStephen Hemminger 
9861da177e4SLinus Torvalds 		i += len;
9871da177e4SLinus Torvalds 		debug = value;
9881da177e4SLinus Torvalds 		sprintf(pg_result, "OK: debug=%u", debug);
9891da177e4SLinus Torvalds 		return count;
9901da177e4SLinus Torvalds 	}
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 	if (!strcmp(name, "frags")) {
9931da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
99463adc6fbSStephen Hemminger 		if (len < 0)
995222f1806SLuiz Capitulino 			return len;
99663adc6fbSStephen Hemminger 
9971da177e4SLinus Torvalds 		i += len;
9981da177e4SLinus Torvalds 		pkt_dev->nfrags = value;
9991da177e4SLinus Torvalds 		sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
10001da177e4SLinus Torvalds 		return count;
10011da177e4SLinus Torvalds 	}
10021da177e4SLinus Torvalds 	if (!strcmp(name, "delay")) {
10031da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
100463adc6fbSStephen Hemminger 		if (len < 0)
1005222f1806SLuiz Capitulino 			return len;
100663adc6fbSStephen Hemminger 
10071da177e4SLinus Torvalds 		i += len;
1008fd29cf72SStephen Hemminger 		if (value == 0x7FFFFFFF)
1009fd29cf72SStephen Hemminger 			pkt_dev->delay = ULLONG_MAX;
1010fd29cf72SStephen Hemminger 		else
10119240d715SEric Dumazet 			pkt_dev->delay = (u64)value;
1012fd29cf72SStephen Hemminger 
1013fd29cf72SStephen Hemminger 		sprintf(pg_result, "OK: delay=%llu",
1014fd29cf72SStephen Hemminger 			(unsigned long long) pkt_dev->delay);
10151da177e4SLinus Torvalds 		return count;
10161da177e4SLinus Torvalds 	}
101743d28b65SDaniel Turull 	if (!strcmp(name, "rate")) {
101843d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
101943d28b65SDaniel Turull 		if (len < 0)
102043d28b65SDaniel Turull 			return len;
102143d28b65SDaniel Turull 
102243d28b65SDaniel Turull 		i += len;
102343d28b65SDaniel Turull 		if (!value)
102443d28b65SDaniel Turull 			return len;
102543d28b65SDaniel Turull 		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
102643d28b65SDaniel Turull 		if (debug)
1027f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
102843d28b65SDaniel Turull 
102943d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
103043d28b65SDaniel Turull 		return count;
103143d28b65SDaniel Turull 	}
103243d28b65SDaniel Turull 	if (!strcmp(name, "ratep")) {
103343d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
103443d28b65SDaniel Turull 		if (len < 0)
103543d28b65SDaniel Turull 			return len;
103643d28b65SDaniel Turull 
103743d28b65SDaniel Turull 		i += len;
103843d28b65SDaniel Turull 		if (!value)
103943d28b65SDaniel Turull 			return len;
104043d28b65SDaniel Turull 		pkt_dev->delay = NSEC_PER_SEC/value;
104143d28b65SDaniel Turull 		if (debug)
1042f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
104343d28b65SDaniel Turull 
104443d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
104543d28b65SDaniel Turull 		return count;
104643d28b65SDaniel Turull 	}
10471da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_min")) {
10481da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
104963adc6fbSStephen Hemminger 		if (len < 0)
1050222f1806SLuiz Capitulino 			return len;
105163adc6fbSStephen Hemminger 
10521da177e4SLinus Torvalds 		i += len;
10531da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_min) {
10541da177e4SLinus Torvalds 			pkt_dev->udp_src_min = value;
10551da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10561da177e4SLinus Torvalds 		}
10571da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
10581da177e4SLinus Torvalds 		return count;
10591da177e4SLinus Torvalds 	}
10601da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_min")) {
10611da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
106263adc6fbSStephen Hemminger 		if (len < 0)
1063222f1806SLuiz Capitulino 			return len;
106463adc6fbSStephen Hemminger 
10651da177e4SLinus Torvalds 		i += len;
10661da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_min) {
10671da177e4SLinus Torvalds 			pkt_dev->udp_dst_min = value;
10681da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10691da177e4SLinus Torvalds 		}
10701da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
10711da177e4SLinus Torvalds 		return count;
10721da177e4SLinus Torvalds 	}
10731da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_max")) {
10741da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
107563adc6fbSStephen Hemminger 		if (len < 0)
1076222f1806SLuiz Capitulino 			return len;
107763adc6fbSStephen Hemminger 
10781da177e4SLinus Torvalds 		i += len;
10791da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_max) {
10801da177e4SLinus Torvalds 			pkt_dev->udp_src_max = value;
10811da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10821da177e4SLinus Torvalds 		}
10831da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
10841da177e4SLinus Torvalds 		return count;
10851da177e4SLinus Torvalds 	}
10861da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_max")) {
10871da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
108863adc6fbSStephen Hemminger 		if (len < 0)
1089222f1806SLuiz Capitulino 			return len;
109063adc6fbSStephen Hemminger 
10911da177e4SLinus Torvalds 		i += len;
10921da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_max) {
10931da177e4SLinus Torvalds 			pkt_dev->udp_dst_max = value;
10941da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10951da177e4SLinus Torvalds 		}
10961da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
10971da177e4SLinus Torvalds 		return count;
10981da177e4SLinus Torvalds 	}
10991da177e4SLinus Torvalds 	if (!strcmp(name, "clone_skb")) {
11001da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
110163adc6fbSStephen Hemminger 		if (len < 0)
1102222f1806SLuiz Capitulino 			return len;
1103d8873315SNeil Horman 		if ((value > 0) &&
110462f64aedSAlexei Starovoitov 		    ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) ||
110562f64aedSAlexei Starovoitov 		     !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
1106d8873315SNeil Horman 			return -ENOTSUPP;
11071da177e4SLinus Torvalds 		i += len;
11081da177e4SLinus Torvalds 		pkt_dev->clone_skb = value;
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 		sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
11111da177e4SLinus Torvalds 		return count;
11121da177e4SLinus Torvalds 	}
11131da177e4SLinus Torvalds 	if (!strcmp(name, "count")) {
11141da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
111563adc6fbSStephen Hemminger 		if (len < 0)
1116222f1806SLuiz Capitulino 			return len;
111763adc6fbSStephen Hemminger 
11181da177e4SLinus Torvalds 		i += len;
11191da177e4SLinus Torvalds 		pkt_dev->count = value;
11201da177e4SLinus Torvalds 		sprintf(pg_result, "OK: count=%llu",
11211da177e4SLinus Torvalds 			(unsigned long long)pkt_dev->count);
11221da177e4SLinus Torvalds 		return count;
11231da177e4SLinus Torvalds 	}
11241da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac_count")) {
11251da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
112663adc6fbSStephen Hemminger 		if (len < 0)
1127222f1806SLuiz Capitulino 			return len;
112863adc6fbSStephen Hemminger 
11291da177e4SLinus Torvalds 		i += len;
11301da177e4SLinus Torvalds 		if (pkt_dev->src_mac_count != value) {
11311da177e4SLinus Torvalds 			pkt_dev->src_mac_count = value;
11321da177e4SLinus Torvalds 			pkt_dev->cur_src_mac_offset = 0;
11331da177e4SLinus Torvalds 		}
1134222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: src_mac_count=%d",
1135222f1806SLuiz Capitulino 			pkt_dev->src_mac_count);
11361da177e4SLinus Torvalds 		return count;
11371da177e4SLinus Torvalds 	}
11381da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac_count")) {
11391da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
114063adc6fbSStephen Hemminger 		if (len < 0)
1141222f1806SLuiz Capitulino 			return len;
114263adc6fbSStephen Hemminger 
11431da177e4SLinus Torvalds 		i += len;
11441da177e4SLinus Torvalds 		if (pkt_dev->dst_mac_count != value) {
11451da177e4SLinus Torvalds 			pkt_dev->dst_mac_count = value;
11461da177e4SLinus Torvalds 			pkt_dev->cur_dst_mac_offset = 0;
11471da177e4SLinus Torvalds 		}
1148222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: dst_mac_count=%d",
1149222f1806SLuiz Capitulino 			pkt_dev->dst_mac_count);
11501da177e4SLinus Torvalds 		return count;
11511da177e4SLinus Torvalds 	}
115238b2cf29SAlexei Starovoitov 	if (!strcmp(name, "burst")) {
115338b2cf29SAlexei Starovoitov 		len = num_arg(&user_buffer[i], 10, &value);
115438b2cf29SAlexei Starovoitov 		if (len < 0)
115538b2cf29SAlexei Starovoitov 			return len;
115638b2cf29SAlexei Starovoitov 
115738b2cf29SAlexei Starovoitov 		i += len;
11580967f244SJohn Fastabend 		if ((value > 1) &&
11590967f244SJohn Fastabend 		    ((pkt_dev->xmit_mode == M_QUEUE_XMIT) ||
11600967f244SJohn Fastabend 		     ((pkt_dev->xmit_mode == M_START_XMIT) &&
11610967f244SJohn Fastabend 		     (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))))
116252d6c8c6SEric Dumazet 			return -ENOTSUPP;
116338b2cf29SAlexei Starovoitov 		pkt_dev->burst = value < 1 ? 1 : value;
116438b2cf29SAlexei Starovoitov 		sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
116538b2cf29SAlexei Starovoitov 		return count;
116638b2cf29SAlexei Starovoitov 	}
1167e99b99b4SRobert Olsson 	if (!strcmp(name, "node")) {
1168e99b99b4SRobert Olsson 		len = num_arg(&user_buffer[i], 10, &value);
1169e99b99b4SRobert Olsson 		if (len < 0)
1170e99b99b4SRobert Olsson 			return len;
1171e99b99b4SRobert Olsson 
1172e99b99b4SRobert Olsson 		i += len;
1173e99b99b4SRobert Olsson 
1174e99b99b4SRobert Olsson 		if (node_possible(value)) {
1175e99b99b4SRobert Olsson 			pkt_dev->node = value;
1176e99b99b4SRobert Olsson 			sprintf(pg_result, "OK: node=%d", pkt_dev->node);
117726ad7879SEric Dumazet 			if (pkt_dev->page) {
117826ad7879SEric Dumazet 				put_page(pkt_dev->page);
117926ad7879SEric Dumazet 				pkt_dev->page = NULL;
118026ad7879SEric Dumazet 			}
1181e99b99b4SRobert Olsson 		}
1182e99b99b4SRobert Olsson 		else
1183e99b99b4SRobert Olsson 			sprintf(pg_result, "ERROR: node not possible");
1184e99b99b4SRobert Olsson 		return count;
1185e99b99b4SRobert Olsson 	}
118662f64aedSAlexei Starovoitov 	if (!strcmp(name, "xmit_mode")) {
118762f64aedSAlexei Starovoitov 		char f[32];
118862f64aedSAlexei Starovoitov 
118962f64aedSAlexei Starovoitov 		memset(f, 0, 32);
119062f64aedSAlexei Starovoitov 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
119162f64aedSAlexei Starovoitov 		if (len < 0)
119262f64aedSAlexei Starovoitov 			return len;
119362f64aedSAlexei Starovoitov 
119462f64aedSAlexei Starovoitov 		if (copy_from_user(f, &user_buffer[i], len))
119562f64aedSAlexei Starovoitov 			return -EFAULT;
119662f64aedSAlexei Starovoitov 		i += len;
119762f64aedSAlexei Starovoitov 
119862f64aedSAlexei Starovoitov 		if (strcmp(f, "start_xmit") == 0) {
119962f64aedSAlexei Starovoitov 			pkt_dev->xmit_mode = M_START_XMIT;
120062f64aedSAlexei Starovoitov 		} else if (strcmp(f, "netif_receive") == 0) {
120162f64aedSAlexei Starovoitov 			/* clone_skb set earlier, not supported in this mode */
120262f64aedSAlexei Starovoitov 			if (pkt_dev->clone_skb > 0)
120362f64aedSAlexei Starovoitov 				return -ENOTSUPP;
120462f64aedSAlexei Starovoitov 
120562f64aedSAlexei Starovoitov 			pkt_dev->xmit_mode = M_NETIF_RECEIVE;
12069eea9222SAlexei Starovoitov 
12079eea9222SAlexei Starovoitov 			/* make sure new packet is allocated every time
12089eea9222SAlexei Starovoitov 			 * pktgen_xmit() is called
12099eea9222SAlexei Starovoitov 			 */
12109eea9222SAlexei Starovoitov 			pkt_dev->last_ok = 1;
12119eea9222SAlexei Starovoitov 
12129eea9222SAlexei Starovoitov 			/* override clone_skb if user passed default value
12139eea9222SAlexei Starovoitov 			 * at module loading time
12149eea9222SAlexei Starovoitov 			 */
12159eea9222SAlexei Starovoitov 			pkt_dev->clone_skb = 0;
12160967f244SJohn Fastabend 		} else if (strcmp(f, "queue_xmit") == 0) {
12170967f244SJohn Fastabend 			pkt_dev->xmit_mode = M_QUEUE_XMIT;
12180967f244SJohn Fastabend 			pkt_dev->last_ok = 1;
121962f64aedSAlexei Starovoitov 		} else {
122062f64aedSAlexei Starovoitov 			sprintf(pg_result,
122162f64aedSAlexei Starovoitov 				"xmit_mode -:%s:- unknown\nAvailable modes: %s",
122262f64aedSAlexei Starovoitov 				f, "start_xmit, netif_receive\n");
122362f64aedSAlexei Starovoitov 			return count;
122462f64aedSAlexei Starovoitov 		}
122562f64aedSAlexei Starovoitov 		sprintf(pg_result, "OK: xmit_mode=%s", f);
122662f64aedSAlexei Starovoitov 		return count;
122762f64aedSAlexei Starovoitov 	}
12281da177e4SLinus Torvalds 	if (!strcmp(name, "flag")) {
12291da177e4SLinus Torvalds 		char f[32];
12301da177e4SLinus Torvalds 		memset(f, 0, 32);
12311da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
123263adc6fbSStephen Hemminger 		if (len < 0)
1233222f1806SLuiz Capitulino 			return len;
123463adc6fbSStephen Hemminger 
12351da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
12361da177e4SLinus Torvalds 			return -EFAULT;
12371da177e4SLinus Torvalds 		i += len;
12381da177e4SLinus Torvalds 		if (strcmp(f, "IPSRC_RND") == 0)
12391da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPSRC_RND;
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds 		else if (strcmp(f, "!IPSRC_RND") == 0)
12421da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPSRC_RND;
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 		else if (strcmp(f, "TXSIZE_RND") == 0)
12451da177e4SLinus Torvalds 			pkt_dev->flags |= F_TXSIZE_RND;
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 		else if (strcmp(f, "!TXSIZE_RND") == 0)
12481da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_TXSIZE_RND;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 		else if (strcmp(f, "IPDST_RND") == 0)
12511da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPDST_RND;
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds 		else if (strcmp(f, "!IPDST_RND") == 0)
12541da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPDST_RND;
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds 		else if (strcmp(f, "UDPSRC_RND") == 0)
12571da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPSRC_RND;
12581da177e4SLinus Torvalds 
12591da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPSRC_RND") == 0)
12601da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPSRC_RND;
12611da177e4SLinus Torvalds 
12621da177e4SLinus Torvalds 		else if (strcmp(f, "UDPDST_RND") == 0)
12631da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPDST_RND;
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPDST_RND") == 0)
12661da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPDST_RND;
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds 		else if (strcmp(f, "MACSRC_RND") == 0)
12691da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACSRC_RND;
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 		else if (strcmp(f, "!MACSRC_RND") == 0)
12721da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACSRC_RND;
12731da177e4SLinus Torvalds 
12741da177e4SLinus Torvalds 		else if (strcmp(f, "MACDST_RND") == 0)
12751da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACDST_RND;
12761da177e4SLinus Torvalds 
12771da177e4SLinus Torvalds 		else if (strcmp(f, "!MACDST_RND") == 0)
12781da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACDST_RND;
12791da177e4SLinus Torvalds 
1280ca6549afSSteven Whitehouse 		else if (strcmp(f, "MPLS_RND") == 0)
1281ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
1282ca6549afSSteven Whitehouse 
1283ca6549afSSteven Whitehouse 		else if (strcmp(f, "!MPLS_RND") == 0)
1284ca6549afSSteven Whitehouse 			pkt_dev->flags &= ~F_MPLS_RND;
1285ca6549afSSteven Whitehouse 
128634954ddcSFrancesco Fondelli 		else if (strcmp(f, "VID_RND") == 0)
128734954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_VID_RND;
128834954ddcSFrancesco Fondelli 
128934954ddcSFrancesco Fondelli 		else if (strcmp(f, "!VID_RND") == 0)
129034954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_VID_RND;
129134954ddcSFrancesco Fondelli 
129234954ddcSFrancesco Fondelli 		else if (strcmp(f, "SVID_RND") == 0)
129334954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_SVID_RND;
129434954ddcSFrancesco Fondelli 
129534954ddcSFrancesco Fondelli 		else if (strcmp(f, "!SVID_RND") == 0)
129634954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_SVID_RND;
129734954ddcSFrancesco Fondelli 
129857a5749bSDmitry Safonov 		else if (strcmp(f, "FLOW_SEQ") == 0 || strcmp(f, "!FLOW_RND") == 0)
1299007a531bSJamal Hadi Salim 			pkt_dev->flags |= F_FLOW_SEQ;
1300007a531bSJamal Hadi Salim 
130157a5749bSDmitry Safonov 		else if (strcmp(f, "FLOW_RND") == 0 || strcmp(f, "!FLOW_SEQ") == 0)
130257a5749bSDmitry Safonov 			pkt_dev->flags &= ~F_FLOW_SEQ;
130357a5749bSDmitry Safonov 
130445b270f8SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_RND") == 0)
130545b270f8SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_RND;
130645b270f8SRobert Olsson 
130745b270f8SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_RND") == 0)
130845b270f8SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_RND;
1309e6fce5b9SRobert Olsson 
1310e6fce5b9SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_CPU") == 0)
1311e6fce5b9SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_CPU;
1312e6fce5b9SRobert Olsson 
1313e6fce5b9SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_CPU") == 0)
1314e6fce5b9SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
1315a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
1316a553e4a6SJamal Hadi Salim 		else if (strcmp(f, "IPSEC") == 0)
1317*6f107c74SDmitry Safonov 			pkt_dev->flags |= F_IPSEC;
131857a5749bSDmitry Safonov 
131957a5749bSDmitry Safonov 		else if (strcmp(f, "!IPSEC") == 0)
1320*6f107c74SDmitry Safonov 			pkt_dev->flags &= ~F_IPSEC;
1321a553e4a6SJamal Hadi Salim #endif
1322a553e4a6SJamal Hadi Salim 
13231ca7768cSFrancesco Fondelli 		else if (strcmp(f, "!IPV6") == 0)
13241ca7768cSFrancesco Fondelli 			pkt_dev->flags &= ~F_IPV6;
13251ca7768cSFrancesco Fondelli 
1326e99b99b4SRobert Olsson 		else if (strcmp(f, "NODE_ALLOC") == 0)
1327e99b99b4SRobert Olsson 			pkt_dev->flags |= F_NODE;
1328e99b99b4SRobert Olsson 
1329e99b99b4SRobert Olsson 		else if (strcmp(f, "!NODE_ALLOC") == 0)
1330e99b99b4SRobert Olsson 			pkt_dev->flags &= ~F_NODE;
1331e99b99b4SRobert Olsson 
1332c26bf4a5SThomas Graf 		else if (strcmp(f, "UDPCSUM") == 0)
1333c26bf4a5SThomas Graf 			pkt_dev->flags |= F_UDPCSUM;
1334c26bf4a5SThomas Graf 
1335c26bf4a5SThomas Graf 		else if (strcmp(f, "!UDPCSUM") == 0)
1336c26bf4a5SThomas Graf 			pkt_dev->flags &= ~F_UDPCSUM;
1337c26bf4a5SThomas Graf 
1338afb84b62SJesper Dangaard Brouer 		else if (strcmp(f, "NO_TIMESTAMP") == 0)
1339afb84b62SJesper Dangaard Brouer 			pkt_dev->flags |= F_NO_TIMESTAMP;
1340afb84b62SJesper Dangaard Brouer 
1341f1f00d8fSJesper Dangaard Brouer 		else if (strcmp(f, "!NO_TIMESTAMP") == 0)
1342f1f00d8fSJesper Dangaard Brouer 			pkt_dev->flags &= ~F_NO_TIMESTAMP;
1343f1f00d8fSJesper Dangaard Brouer 
13441da177e4SLinus Torvalds 		else {
1345222f1806SLuiz Capitulino 			sprintf(pg_result,
1346222f1806SLuiz Capitulino 				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
13471da177e4SLinus Torvalds 				f,
13481ca7768cSFrancesco Fondelli 				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
134972f8e06fSMathias Krause 				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
135072f8e06fSMathias Krause 				"MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
135172f8e06fSMathias Krause 				"QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
1352afb84b62SJesper Dangaard Brouer 				"NO_TIMESTAMP, "
135372f8e06fSMathias Krause #ifdef CONFIG_XFRM
135472f8e06fSMathias Krause 				"IPSEC, "
135572f8e06fSMathias Krause #endif
135672f8e06fSMathias Krause 				"NODE_ALLOC\n");
13571da177e4SLinus Torvalds 			return count;
13581da177e4SLinus Torvalds 		}
13591da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
13601da177e4SLinus Torvalds 		return count;
13611da177e4SLinus Torvalds 	}
13621da177e4SLinus Torvalds 	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
13631da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
136463adc6fbSStephen Hemminger 		if (len < 0)
1365222f1806SLuiz Capitulino 			return len;
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13681da177e4SLinus Torvalds 			return -EFAULT;
13691da177e4SLinus Torvalds 		buf[len] = 0;
13701da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_min) != 0) {
13711da177e4SLinus Torvalds 			memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
13721da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_min, buf, len);
13731da177e4SLinus Torvalds 			pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
13741da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_min;
13751da177e4SLinus Torvalds 		}
13761da177e4SLinus Torvalds 		if (debug)
1377f342cda7SJoe Perches 			pr_debug("dst_min set to: %s\n", pkt_dev->dst_min);
13781da177e4SLinus Torvalds 		i += len;
13791da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
13801da177e4SLinus Torvalds 		return count;
13811da177e4SLinus Torvalds 	}
13821da177e4SLinus Torvalds 	if (!strcmp(name, "dst_max")) {
13831da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
138463adc6fbSStephen Hemminger 		if (len < 0)
1385222f1806SLuiz Capitulino 			return len;
138663adc6fbSStephen Hemminger 
13871da177e4SLinus Torvalds 
13881da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13891da177e4SLinus Torvalds 			return -EFAULT;
13901da177e4SLinus Torvalds 
13911da177e4SLinus Torvalds 		buf[len] = 0;
13921da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_max) != 0) {
13931da177e4SLinus Torvalds 			memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
13941da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_max, buf, len);
13951da177e4SLinus Torvalds 			pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
13961da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_max;
13971da177e4SLinus Torvalds 		}
13981da177e4SLinus Torvalds 		if (debug)
1399f342cda7SJoe Perches 			pr_debug("dst_max set to: %s\n", pkt_dev->dst_max);
14001da177e4SLinus Torvalds 		i += len;
14011da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
14021da177e4SLinus Torvalds 		return count;
14031da177e4SLinus Torvalds 	}
14041da177e4SLinus Torvalds 	if (!strcmp(name, "dst6")) {
14051da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1406222f1806SLuiz Capitulino 		if (len < 0)
1407222f1806SLuiz Capitulino 			return len;
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14121da177e4SLinus Torvalds 			return -EFAULT;
14131da177e4SLinus Torvalds 		buf[len] = 0;
14141da177e4SLinus Torvalds 
1415c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL);
141647a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
14171da177e4SLinus Torvalds 
14184e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr;
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 		if (debug)
1421f342cda7SJoe Perches 			pr_debug("dst6 set to: %s\n", buf);
14221da177e4SLinus Torvalds 
14231da177e4SLinus Torvalds 		i += len;
14241da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6=%s", buf);
14251da177e4SLinus Torvalds 		return count;
14261da177e4SLinus Torvalds 	}
14271da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_min")) {
14281da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1429222f1806SLuiz Capitulino 		if (len < 0)
1430222f1806SLuiz Capitulino 			return len;
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14351da177e4SLinus Torvalds 			return -EFAULT;
14361da177e4SLinus Torvalds 		buf[len] = 0;
14371da177e4SLinus Torvalds 
1438c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL);
143947a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
14401da177e4SLinus Torvalds 
14414e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr;
14421da177e4SLinus Torvalds 		if (debug)
1443f342cda7SJoe Perches 			pr_debug("dst6_min set to: %s\n", buf);
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 		i += len;
14461da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_min=%s", buf);
14471da177e4SLinus Torvalds 		return count;
14481da177e4SLinus Torvalds 	}
14491da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_max")) {
14501da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1451222f1806SLuiz Capitulino 		if (len < 0)
1452222f1806SLuiz Capitulino 			return len;
14531da177e4SLinus Torvalds 
14541da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14571da177e4SLinus Torvalds 			return -EFAULT;
14581da177e4SLinus Torvalds 		buf[len] = 0;
14591da177e4SLinus Torvalds 
1460c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL);
146147a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
14621da177e4SLinus Torvalds 
14631da177e4SLinus Torvalds 		if (debug)
1464f342cda7SJoe Perches 			pr_debug("dst6_max set to: %s\n", buf);
14651da177e4SLinus Torvalds 
14661da177e4SLinus Torvalds 		i += len;
14671da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_max=%s", buf);
14681da177e4SLinus Torvalds 		return count;
14691da177e4SLinus Torvalds 	}
14701da177e4SLinus Torvalds 	if (!strcmp(name, "src6")) {
14711da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1472222f1806SLuiz Capitulino 		if (len < 0)
1473222f1806SLuiz Capitulino 			return len;
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14781da177e4SLinus Torvalds 			return -EFAULT;
14791da177e4SLinus Torvalds 		buf[len] = 0;
14801da177e4SLinus Torvalds 
1481c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL);
148247a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
14831da177e4SLinus Torvalds 
14844e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr;
14851da177e4SLinus Torvalds 
14861da177e4SLinus Torvalds 		if (debug)
1487f342cda7SJoe Perches 			pr_debug("src6 set to: %s\n", buf);
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds 		i += len;
14901da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src6=%s", buf);
14911da177e4SLinus Torvalds 		return count;
14921da177e4SLinus Torvalds 	}
14931da177e4SLinus Torvalds 	if (!strcmp(name, "src_min")) {
14941da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
149563adc6fbSStephen Hemminger 		if (len < 0)
1496222f1806SLuiz Capitulino 			return len;
149763adc6fbSStephen Hemminger 
14981da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14991da177e4SLinus Torvalds 			return -EFAULT;
15001da177e4SLinus Torvalds 		buf[len] = 0;
15011da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_min) != 0) {
15021da177e4SLinus Torvalds 			memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
15031da177e4SLinus Torvalds 			strncpy(pkt_dev->src_min, buf, len);
15041da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
15051da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_min;
15061da177e4SLinus Torvalds 		}
15071da177e4SLinus Torvalds 		if (debug)
1508f342cda7SJoe Perches 			pr_debug("src_min set to: %s\n", pkt_dev->src_min);
15091da177e4SLinus Torvalds 		i += len;
15101da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
15111da177e4SLinus Torvalds 		return count;
15121da177e4SLinus Torvalds 	}
15131da177e4SLinus Torvalds 	if (!strcmp(name, "src_max")) {
15141da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
151563adc6fbSStephen Hemminger 		if (len < 0)
1516222f1806SLuiz Capitulino 			return len;
151763adc6fbSStephen Hemminger 
15181da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
15191da177e4SLinus Torvalds 			return -EFAULT;
15201da177e4SLinus Torvalds 		buf[len] = 0;
15211da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_max) != 0) {
15221da177e4SLinus Torvalds 			memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
15231da177e4SLinus Torvalds 			strncpy(pkt_dev->src_max, buf, len);
15241da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
15251da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_max;
15261da177e4SLinus Torvalds 		}
15271da177e4SLinus Torvalds 		if (debug)
1528f342cda7SJoe Perches 			pr_debug("src_max set to: %s\n", pkt_dev->src_max);
15291da177e4SLinus Torvalds 		i += len;
15301da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
15311da177e4SLinus Torvalds 		return count;
15321da177e4SLinus Torvalds 	}
15331da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac")) {
15341da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
153563adc6fbSStephen Hemminger 		if (len < 0)
1536222f1806SLuiz Capitulino 			return len;
153763adc6fbSStephen Hemminger 
15381da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
15391da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
15401da177e4SLinus Torvalds 			return -EFAULT;
15411da177e4SLinus Torvalds 
15424940fc88SAlexey Dobriyan 		if (!mac_pton(valstr, pkt_dev->dst_mac))
15434940fc88SAlexey Dobriyan 			return -EINVAL;
15441da177e4SLinus Torvalds 		/* Set up Dest MAC */
15459ea08b12SJoe Perches 		ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac);
15461da177e4SLinus Torvalds 
15474940fc88SAlexey Dobriyan 		sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
15481da177e4SLinus Torvalds 		return count;
15491da177e4SLinus Torvalds 	}
15501da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac")) {
15511da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
155263adc6fbSStephen Hemminger 		if (len < 0)
1553222f1806SLuiz Capitulino 			return len;
155463adc6fbSStephen Hemminger 
15551da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
15561da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
15571da177e4SLinus Torvalds 			return -EFAULT;
15581da177e4SLinus Torvalds 
15594940fc88SAlexey Dobriyan 		if (!mac_pton(valstr, pkt_dev->src_mac))
15604940fc88SAlexey Dobriyan 			return -EINVAL;
1561ce5d0b47SAdit Ranadive 		/* Set up Src MAC */
15629ea08b12SJoe Perches 		ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac);
1563ce5d0b47SAdit Ranadive 
15644940fc88SAlexey Dobriyan 		sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
15651da177e4SLinus Torvalds 		return count;
15661da177e4SLinus Torvalds 	}
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds 	if (!strcmp(name, "clear_counters")) {
15691da177e4SLinus Torvalds 		pktgen_clear_counters(pkt_dev);
15701da177e4SLinus Torvalds 		sprintf(pg_result, "OK: Clearing counters.\n");
15711da177e4SLinus Torvalds 		return count;
15721da177e4SLinus Torvalds 	}
15731da177e4SLinus Torvalds 
15741da177e4SLinus Torvalds 	if (!strcmp(name, "flows")) {
15751da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
157663adc6fbSStephen Hemminger 		if (len < 0)
1577222f1806SLuiz Capitulino 			return len;
157863adc6fbSStephen Hemminger 
15791da177e4SLinus Torvalds 		i += len;
15801da177e4SLinus Torvalds 		if (value > MAX_CFLOWS)
15811da177e4SLinus Torvalds 			value = MAX_CFLOWS;
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 		pkt_dev->cflows = value;
15841da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
15851da177e4SLinus Torvalds 		return count;
15861da177e4SLinus Torvalds 	}
15876bae9190SFan Du #ifdef CONFIG_XFRM
1588de4aee7dSFan Du 	if (!strcmp(name, "spi")) {
1589de4aee7dSFan Du 		len = num_arg(&user_buffer[i], 10, &value);
1590de4aee7dSFan Du 		if (len < 0)
1591de4aee7dSFan Du 			return len;
1592de4aee7dSFan Du 
1593de4aee7dSFan Du 		i += len;
1594de4aee7dSFan Du 		pkt_dev->spi = value;
1595de4aee7dSFan Du 		sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
1596de4aee7dSFan Du 		return count;
1597de4aee7dSFan Du 	}
15986bae9190SFan Du #endif
15991da177e4SLinus Torvalds 	if (!strcmp(name, "flowlen")) {
16001da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
160163adc6fbSStephen Hemminger 		if (len < 0)
1602222f1806SLuiz Capitulino 			return len;
160363adc6fbSStephen Hemminger 
16041da177e4SLinus Torvalds 		i += len;
16051da177e4SLinus Torvalds 		pkt_dev->lflow = value;
16061da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
16071da177e4SLinus Torvalds 		return count;
16081da177e4SLinus Torvalds 	}
16091da177e4SLinus Torvalds 
161045b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_min")) {
161145b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
161263adc6fbSStephen Hemminger 		if (len < 0)
161345b270f8SRobert Olsson 			return len;
161463adc6fbSStephen Hemminger 
161545b270f8SRobert Olsson 		i += len;
161645b270f8SRobert Olsson 		pkt_dev->queue_map_min = value;
161745b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
161845b270f8SRobert Olsson 		return count;
161945b270f8SRobert Olsson 	}
162045b270f8SRobert Olsson 
162145b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_max")) {
162245b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
162363adc6fbSStephen Hemminger 		if (len < 0)
162445b270f8SRobert Olsson 			return len;
162563adc6fbSStephen Hemminger 
162645b270f8SRobert Olsson 		i += len;
162745b270f8SRobert Olsson 		pkt_dev->queue_map_max = value;
162845b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
162945b270f8SRobert Olsson 		return count;
163045b270f8SRobert Olsson 	}
163145b270f8SRobert Olsson 
1632ca6549afSSteven Whitehouse 	if (!strcmp(name, "mpls")) {
163395c96174SEric Dumazet 		unsigned int n, cnt;
1634cfcabdccSStephen Hemminger 
1635ca6549afSSteven Whitehouse 		len = get_labels(&user_buffer[i], pkt_dev);
1636cfcabdccSStephen Hemminger 		if (len < 0)
1637cfcabdccSStephen Hemminger 			return len;
1638ca6549afSSteven Whitehouse 		i += len;
1639cfcabdccSStephen Hemminger 		cnt = sprintf(pg_result, "OK: mpls=");
1640ca6549afSSteven Whitehouse 		for (n = 0; n < pkt_dev->nr_labels; n++)
1641cfcabdccSStephen Hemminger 			cnt += sprintf(pg_result + cnt,
1642ca6549afSSteven Whitehouse 				       "%08x%s", ntohl(pkt_dev->labels[n]),
1643ca6549afSSteven Whitehouse 				       n == pkt_dev->nr_labels-1 ? "" : ",");
164434954ddcSFrancesco Fondelli 
164534954ddcSFrancesco Fondelli 		if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
164634954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
164734954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
164834954ddcSFrancesco Fondelli 
164934954ddcSFrancesco Fondelli 			if (debug)
1650f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN auto turned off\n");
165134954ddcSFrancesco Fondelli 		}
165234954ddcSFrancesco Fondelli 		return count;
165334954ddcSFrancesco Fondelli 	}
165434954ddcSFrancesco Fondelli 
165534954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_id")) {
165634954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
165763adc6fbSStephen Hemminger 		if (len < 0)
165834954ddcSFrancesco Fondelli 			return len;
165963adc6fbSStephen Hemminger 
166034954ddcSFrancesco Fondelli 		i += len;
166134954ddcSFrancesco Fondelli 		if (value <= 4095) {
166234954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = value;  /* turn on VLAN */
166334954ddcSFrancesco Fondelli 
166434954ddcSFrancesco Fondelli 			if (debug)
1665f342cda7SJoe Perches 				pr_debug("VLAN turned on\n");
166634954ddcSFrancesco Fondelli 
166734954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
1668f342cda7SJoe Perches 				pr_debug("MPLS auto turned off\n");
166934954ddcSFrancesco Fondelli 
167034954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
167134954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
167234954ddcSFrancesco Fondelli 		} else {
167334954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
167434954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
167534954ddcSFrancesco Fondelli 
167634954ddcSFrancesco Fondelli 			if (debug)
1677f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN turned off\n");
167834954ddcSFrancesco Fondelli 		}
167934954ddcSFrancesco Fondelli 		return count;
168034954ddcSFrancesco Fondelli 	}
168134954ddcSFrancesco Fondelli 
168234954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_p")) {
168334954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
168463adc6fbSStephen Hemminger 		if (len < 0)
168534954ddcSFrancesco Fondelli 			return len;
168663adc6fbSStephen Hemminger 
168734954ddcSFrancesco Fondelli 		i += len;
168834954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
168934954ddcSFrancesco Fondelli 			pkt_dev->vlan_p = value;
169034954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
169134954ddcSFrancesco Fondelli 		} else {
169234954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_p must be 0-7");
169334954ddcSFrancesco Fondelli 		}
169434954ddcSFrancesco Fondelli 		return count;
169534954ddcSFrancesco Fondelli 	}
169634954ddcSFrancesco Fondelli 
169734954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_cfi")) {
169834954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
169963adc6fbSStephen Hemminger 		if (len < 0)
170034954ddcSFrancesco Fondelli 			return len;
170163adc6fbSStephen Hemminger 
170234954ddcSFrancesco Fondelli 		i += len;
170334954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
170434954ddcSFrancesco Fondelli 			pkt_dev->vlan_cfi = value;
170534954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
170634954ddcSFrancesco Fondelli 		} else {
170734954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
170834954ddcSFrancesco Fondelli 		}
170934954ddcSFrancesco Fondelli 		return count;
171034954ddcSFrancesco Fondelli 	}
171134954ddcSFrancesco Fondelli 
171234954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_id")) {
171334954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
171463adc6fbSStephen Hemminger 		if (len < 0)
171534954ddcSFrancesco Fondelli 			return len;
171663adc6fbSStephen Hemminger 
171734954ddcSFrancesco Fondelli 		i += len;
171834954ddcSFrancesco Fondelli 		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
171934954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = value;  /* turn on SVLAN */
172034954ddcSFrancesco Fondelli 
172134954ddcSFrancesco Fondelli 			if (debug)
1722f342cda7SJoe Perches 				pr_debug("SVLAN turned on\n");
172334954ddcSFrancesco Fondelli 
172434954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
1725f342cda7SJoe Perches 				pr_debug("MPLS auto turned off\n");
172634954ddcSFrancesco Fondelli 
172734954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
172834954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
172934954ddcSFrancesco Fondelli 		} else {
173034954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
173134954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
173234954ddcSFrancesco Fondelli 
173334954ddcSFrancesco Fondelli 			if (debug)
1734f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN turned off\n");
173534954ddcSFrancesco Fondelli 		}
173634954ddcSFrancesco Fondelli 		return count;
173734954ddcSFrancesco Fondelli 	}
173834954ddcSFrancesco Fondelli 
173934954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_p")) {
174034954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
174163adc6fbSStephen Hemminger 		if (len < 0)
174234954ddcSFrancesco Fondelli 			return len;
174363adc6fbSStephen Hemminger 
174434954ddcSFrancesco Fondelli 		i += len;
174534954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
174634954ddcSFrancesco Fondelli 			pkt_dev->svlan_p = value;
174734954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
174834954ddcSFrancesco Fondelli 		} else {
174934954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_p must be 0-7");
175034954ddcSFrancesco Fondelli 		}
175134954ddcSFrancesco Fondelli 		return count;
175234954ddcSFrancesco Fondelli 	}
175334954ddcSFrancesco Fondelli 
175434954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_cfi")) {
175534954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
175663adc6fbSStephen Hemminger 		if (len < 0)
175734954ddcSFrancesco Fondelli 			return len;
175863adc6fbSStephen Hemminger 
175934954ddcSFrancesco Fondelli 		i += len;
176034954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
176134954ddcSFrancesco Fondelli 			pkt_dev->svlan_cfi = value;
176234954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
176334954ddcSFrancesco Fondelli 		} else {
176434954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
176534954ddcSFrancesco Fondelli 		}
1766ca6549afSSteven Whitehouse 		return count;
1767ca6549afSSteven Whitehouse 	}
1768ca6549afSSteven Whitehouse 
17691ca7768cSFrancesco Fondelli 	if (!strcmp(name, "tos")) {
17701ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
17711ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
177263adc6fbSStephen Hemminger 		if (len < 0)
17731ca7768cSFrancesco Fondelli 			return len;
177463adc6fbSStephen Hemminger 
17751ca7768cSFrancesco Fondelli 		i += len;
17761ca7768cSFrancesco Fondelli 		if (len == 2) {
17771ca7768cSFrancesco Fondelli 			pkt_dev->tos = tmp_value;
17781ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
17791ca7768cSFrancesco Fondelli 		} else {
17801ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: tos must be 00-ff");
17811ca7768cSFrancesco Fondelli 		}
17821ca7768cSFrancesco Fondelli 		return count;
17831ca7768cSFrancesco Fondelli 	}
17841ca7768cSFrancesco Fondelli 
17851ca7768cSFrancesco Fondelli 	if (!strcmp(name, "traffic_class")) {
17861ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
17871ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
178863adc6fbSStephen Hemminger 		if (len < 0)
17891ca7768cSFrancesco Fondelli 			return len;
179063adc6fbSStephen Hemminger 
17911ca7768cSFrancesco Fondelli 		i += len;
17921ca7768cSFrancesco Fondelli 		if (len == 2) {
17931ca7768cSFrancesco Fondelli 			pkt_dev->traffic_class = tmp_value;
17941ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
17951ca7768cSFrancesco Fondelli 		} else {
17961ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
17971ca7768cSFrancesco Fondelli 		}
17981ca7768cSFrancesco Fondelli 		return count;
17991ca7768cSFrancesco Fondelli 	}
18001ca7768cSFrancesco Fondelli 
18019e50e3acSJohn Fastabend 	if (!strcmp(name, "skb_priority")) {
18029e50e3acSJohn Fastabend 		len = num_arg(&user_buffer[i], 9, &value);
18039e50e3acSJohn Fastabend 		if (len < 0)
18049e50e3acSJohn Fastabend 			return len;
18059e50e3acSJohn Fastabend 
18069e50e3acSJohn Fastabend 		i += len;
18079e50e3acSJohn Fastabend 		pkt_dev->skb_priority = value;
18089e50e3acSJohn Fastabend 		sprintf(pg_result, "OK: skb_priority=%i",
18099e50e3acSJohn Fastabend 			pkt_dev->skb_priority);
18109e50e3acSJohn Fastabend 		return count;
18119e50e3acSJohn Fastabend 	}
18129e50e3acSJohn Fastabend 
18131da177e4SLinus Torvalds 	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
18141da177e4SLinus Torvalds 	return -EINVAL;
18151da177e4SLinus Torvalds }
18161da177e4SLinus Torvalds 
1817d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file)
18181da177e4SLinus Torvalds {
1819d9dda78bSAl Viro 	return single_open(file, pktgen_if_show, PDE_DATA(inode));
18201da177e4SLinus Torvalds }
18211da177e4SLinus Torvalds 
18229a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = {
1823d50a6b56SStephen Hemminger 	.open    = pktgen_if_open,
1824d50a6b56SStephen Hemminger 	.read    = seq_read,
1825d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1826d50a6b56SStephen Hemminger 	.write   = pktgen_if_write,
1827d50a6b56SStephen Hemminger 	.release = single_release,
1828d50a6b56SStephen Hemminger };
1829d50a6b56SStephen Hemminger 
1830d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v)
1831d50a6b56SStephen Hemminger {
1832d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1833648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
1834d50a6b56SStephen Hemminger 
1835d50a6b56SStephen Hemminger 	BUG_ON(!t);
1836d50a6b56SStephen Hemminger 
183797dc48e2SThomas Graf 	seq_puts(seq, "Running: ");
18381da177e4SLinus Torvalds 
18398788370aSJesper Dangaard Brouer 	rcu_read_lock();
18408788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
18411da177e4SLinus Torvalds 		if (pkt_dev->running)
1842593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
18431da177e4SLinus Torvalds 
184497dc48e2SThomas Graf 	seq_puts(seq, "\nStopped: ");
18451da177e4SLinus Torvalds 
18468788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
18471da177e4SLinus Torvalds 		if (!pkt_dev->running)
1848593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
18491da177e4SLinus Torvalds 
18501da177e4SLinus Torvalds 	if (t->result[0])
1851d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: %s\n", t->result);
18521da177e4SLinus Torvalds 	else
185397dc48e2SThomas Graf 		seq_puts(seq, "\nResult: NA\n");
18541da177e4SLinus Torvalds 
18558788370aSJesper Dangaard Brouer 	rcu_read_unlock();
18561da177e4SLinus Torvalds 
1857d50a6b56SStephen Hemminger 	return 0;
18581da177e4SLinus Torvalds }
18591da177e4SLinus Torvalds 
1860d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file,
1861d50a6b56SStephen Hemminger 				   const char __user * user_buffer,
1862d50a6b56SStephen Hemminger 				   size_t count, loff_t * offset)
18631da177e4SLinus Torvalds {
18648a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
1865d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1866d6182223SPaul Gortmaker 	int i, max, len, ret;
18671da177e4SLinus Torvalds 	char name[40];
18681da177e4SLinus Torvalds 	char *pg_result;
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds 	if (count < 1) {
18711da177e4SLinus Torvalds 		//      sprintf(pg_result, "Wrong command format");
18721da177e4SLinus Torvalds 		return -EINVAL;
18731da177e4SLinus Torvalds 	}
18741da177e4SLinus Torvalds 
1875d6182223SPaul Gortmaker 	max = count;
1876d6182223SPaul Gortmaker 	len = count_trail_chars(user_buffer, max);
18771da177e4SLinus Torvalds 	if (len < 0)
18781da177e4SLinus Torvalds 		return len;
18791da177e4SLinus Torvalds 
1880d6182223SPaul Gortmaker 	i = len;
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 	/* Read variable name */
18831da177e4SLinus Torvalds 
18841da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
18851da177e4SLinus Torvalds 	if (len < 0)
18861da177e4SLinus Torvalds 		return len;
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
18891da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
18901da177e4SLinus Torvalds 		return -EFAULT;
18911da177e4SLinus Torvalds 	i += len;
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds 	max = count - i;
18941da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
18951da177e4SLinus Torvalds 	if (len < 0)
18961da177e4SLinus Torvalds 		return len;
18971da177e4SLinus Torvalds 
18981da177e4SLinus Torvalds 	i += len;
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds 	if (debug)
1901f342cda7SJoe Perches 		pr_debug("t=%s, count=%lu\n", name, (unsigned long)count);
19021da177e4SLinus Torvalds 
19031da177e4SLinus Torvalds 	if (!t) {
1904f9467eaeSJoe Perches 		pr_err("ERROR: No thread\n");
19051da177e4SLinus Torvalds 		ret = -EINVAL;
19061da177e4SLinus Torvalds 		goto out;
19071da177e4SLinus Torvalds 	}
19081da177e4SLinus Torvalds 
19091da177e4SLinus Torvalds 	pg_result = &(t->result[0]);
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds 	if (!strcmp(name, "add_device")) {
19121da177e4SLinus Torvalds 		char f[32];
19131da177e4SLinus Torvalds 		memset(f, 0, 32);
19141da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
19151da177e4SLinus Torvalds 		if (len < 0) {
19161da177e4SLinus Torvalds 			ret = len;
19171da177e4SLinus Torvalds 			goto out;
19181da177e4SLinus Torvalds 		}
19191da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
19201da177e4SLinus Torvalds 			return -EFAULT;
19211da177e4SLinus Torvalds 		i += len;
19226146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
1923604dfd6eSCong Wang 		ret = pktgen_add_device(t, f);
19246146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1925604dfd6eSCong Wang 		if (!ret) {
19261da177e4SLinus Torvalds 			ret = count;
19271da177e4SLinus Torvalds 			sprintf(pg_result, "OK: add_device=%s", f);
1928604dfd6eSCong Wang 		} else
1929604dfd6eSCong Wang 			sprintf(pg_result, "ERROR: can not add device %s", f);
19301da177e4SLinus Torvalds 		goto out;
19311da177e4SLinus Torvalds 	}
19321da177e4SLinus Torvalds 
19331da177e4SLinus Torvalds 	if (!strcmp(name, "rem_device_all")) {
19346146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
193595ed63f7SArthur Kepner 		t->control |= T_REMDEVALL;
19366146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1937121caf57SNishanth Aravamudan 		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
19381da177e4SLinus Torvalds 		ret = count;
19391da177e4SLinus Torvalds 		sprintf(pg_result, "OK: rem_device_all");
19401da177e4SLinus Torvalds 		goto out;
19411da177e4SLinus Torvalds 	}
19421da177e4SLinus Torvalds 
19431da177e4SLinus Torvalds 	if (!strcmp(name, "max_before_softirq")) {
1944b163911fSRobert Olsson 		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
19451da177e4SLinus Torvalds 		ret = count;
19461da177e4SLinus Torvalds 		goto out;
19471da177e4SLinus Torvalds 	}
19481da177e4SLinus Torvalds 
19491da177e4SLinus Torvalds 	ret = -EINVAL;
19501da177e4SLinus Torvalds out:
19511da177e4SLinus Torvalds 	return ret;
19521da177e4SLinus Torvalds }
19531da177e4SLinus Torvalds 
1954d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file)
19551da177e4SLinus Torvalds {
1956d9dda78bSAl Viro 	return single_open(file, pktgen_thread_show, PDE_DATA(inode));
19571da177e4SLinus Torvalds }
19581da177e4SLinus Torvalds 
19599a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = {
1960d50a6b56SStephen Hemminger 	.open    = pktgen_thread_open,
1961d50a6b56SStephen Hemminger 	.read    = seq_read,
1962d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1963d50a6b56SStephen Hemminger 	.write   = pktgen_thread_write,
1964d50a6b56SStephen Hemminger 	.release = single_release,
1965d50a6b56SStephen Hemminger };
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds /* Think find or remove for NN */
19684e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn,
19694e58a027SCong Wang 					      const char *ifname, int remove)
19701da177e4SLinus Torvalds {
19711da177e4SLinus Torvalds 	struct pktgen_thread *t;
19721da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
19733e984840SEric Dumazet 	bool exact = (remove == FIND);
19741da177e4SLinus Torvalds 
19754e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
19763e984840SEric Dumazet 		pkt_dev = pktgen_find_dev(t, ifname, exact);
19771da177e4SLinus Torvalds 		if (pkt_dev) {
19781da177e4SLinus Torvalds 			if (remove) {
197995ed63f7SArthur Kepner 				pkt_dev->removal_mark = 1;
198095ed63f7SArthur Kepner 				t->control |= T_REMDEV;
19811da177e4SLinus Torvalds 			}
19821da177e4SLinus Torvalds 			break;
19831da177e4SLinus Torvalds 		}
19841da177e4SLinus Torvalds 	}
19851da177e4SLinus Torvalds 	return pkt_dev;
19861da177e4SLinus Torvalds }
19871da177e4SLinus Torvalds 
198895ed63f7SArthur Kepner /*
198995ed63f7SArthur Kepner  * mark a device for removal
199095ed63f7SArthur Kepner  */
19914e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname)
19921da177e4SLinus Torvalds {
19931da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
199495ed63f7SArthur Kepner 	const int max_tries = 10, msec_per_try = 125;
199595ed63f7SArthur Kepner 	int i = 0;
199695ed63f7SArthur Kepner 
19976146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
1998f9467eaeSJoe Perches 	pr_debug("%s: marking %s for removal\n", __func__, ifname);
199995ed63f7SArthur Kepner 
200095ed63f7SArthur Kepner 	while (1) {
200195ed63f7SArthur Kepner 
20024e58a027SCong Wang 		pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE);
2003222f1806SLuiz Capitulino 		if (pkt_dev == NULL)
2004222f1806SLuiz Capitulino 			break;	/* success */
200595ed63f7SArthur Kepner 
20066146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
2007f9467eaeSJoe Perches 		pr_debug("%s: waiting for %s to disappear....\n",
2008f9467eaeSJoe Perches 			 __func__, ifname);
200995ed63f7SArthur Kepner 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
20106146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
201195ed63f7SArthur Kepner 
201295ed63f7SArthur Kepner 		if (++i >= max_tries) {
2013f9467eaeSJoe Perches 			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
2014f9467eaeSJoe Perches 			       __func__, msec_per_try * i, ifname);
201595ed63f7SArthur Kepner 			break;
201695ed63f7SArthur Kepner 		}
201795ed63f7SArthur Kepner 
201895ed63f7SArthur Kepner 	}
201995ed63f7SArthur Kepner 
20206146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
202139df232fSStephen Hemminger }
202295ed63f7SArthur Kepner 
20234e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev)
202439df232fSStephen Hemminger {
202539df232fSStephen Hemminger 	struct pktgen_thread *t;
202639df232fSStephen Hemminger 
20279a0b1e8bSEric Dumazet 	mutex_lock(&pktgen_thread_lock);
20289a0b1e8bSEric Dumazet 
20294e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
203039df232fSStephen Hemminger 		struct pktgen_dev *pkt_dev;
203139df232fSStephen Hemminger 
20329a0b1e8bSEric Dumazet 		if_lock(t);
20339a0b1e8bSEric Dumazet 		list_for_each_entry(pkt_dev, &t->if_list, list) {
203439df232fSStephen Hemminger 			if (pkt_dev->odev != dev)
203539df232fSStephen Hemminger 				continue;
203639df232fSStephen Hemminger 
2037a8ca16eaSDavid Howells 			proc_remove(pkt_dev->entry);
203839df232fSStephen Hemminger 
20392975315bSAlexey Dobriyan 			pkt_dev->entry = proc_create_data(dev->name, 0600,
20404e58a027SCong Wang 							  pn->proc_dir,
20412975315bSAlexey Dobriyan 							  &pktgen_if_fops,
20422975315bSAlexey Dobriyan 							  pkt_dev);
204339df232fSStephen Hemminger 			if (!pkt_dev->entry)
2044f9467eaeSJoe Perches 				pr_err("can't move proc entry for '%s'\n",
2045f9467eaeSJoe Perches 				       dev->name);
204639df232fSStephen Hemminger 			break;
204739df232fSStephen Hemminger 		}
20489a0b1e8bSEric Dumazet 		if_unlock(t);
204939df232fSStephen Hemminger 	}
20509a0b1e8bSEric Dumazet 	mutex_unlock(&pktgen_thread_lock);
20511da177e4SLinus Torvalds }
20521da177e4SLinus Torvalds 
2053222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused,
2054222f1806SLuiz Capitulino 			       unsigned long event, void *ptr)
20551da177e4SLinus Torvalds {
2056351638e7SJiri Pirko 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
20574e58a027SCong Wang 	struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id);
20581da177e4SLinus Torvalds 
20594e58a027SCong Wang 	if (pn->pktgen_exiting)
2060e9dc8653SEric W. Biederman 		return NOTIFY_DONE;
2061e9dc8653SEric W. Biederman 
20621da177e4SLinus Torvalds 	/* It is OK that we do not hold the group lock right now,
20631da177e4SLinus Torvalds 	 * as we run under the RTNL lock.
20641da177e4SLinus Torvalds 	 */
20651da177e4SLinus Torvalds 
20661da177e4SLinus Torvalds 	switch (event) {
206739df232fSStephen Hemminger 	case NETDEV_CHANGENAME:
20684e58a027SCong Wang 		pktgen_change_name(pn, dev);
20691da177e4SLinus Torvalds 		break;
20701da177e4SLinus Torvalds 
20711da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
20724e58a027SCong Wang 		pktgen_mark_device(pn, dev->name);
20731da177e4SLinus Torvalds 		break;
20743ff50b79SStephen Hemminger 	}
20751da177e4SLinus Torvalds 
20761da177e4SLinus Torvalds 	return NOTIFY_DONE;
20771da177e4SLinus Torvalds }
20781da177e4SLinus Torvalds 
20794e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn,
20804e58a027SCong Wang 						 struct pktgen_dev *pkt_dev,
208163adc6fbSStephen Hemminger 						 const char *ifname)
2082e6fce5b9SRobert Olsson {
2083e6fce5b9SRobert Olsson 	char b[IFNAMSIZ+5];
2084d6182223SPaul Gortmaker 	int i;
2085e6fce5b9SRobert Olsson 
2086e6fce5b9SRobert Olsson 	for (i = 0; ifname[i] != '@'; i++) {
2087e6fce5b9SRobert Olsson 		if (i == IFNAMSIZ)
2088e6fce5b9SRobert Olsson 			break;
2089e6fce5b9SRobert Olsson 
2090e6fce5b9SRobert Olsson 		b[i] = ifname[i];
2091e6fce5b9SRobert Olsson 	}
2092e6fce5b9SRobert Olsson 	b[i] = 0;
2093e6fce5b9SRobert Olsson 
20944e58a027SCong Wang 	return dev_get_by_name(pn->net, b);
2095e6fce5b9SRobert Olsson }
2096e6fce5b9SRobert Olsson 
2097e6fce5b9SRobert Olsson 
20981da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */
20991da177e4SLinus Torvalds 
21004e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn,
21014e58a027SCong Wang 			    struct pktgen_dev *pkt_dev, const char *ifname)
2102222f1806SLuiz Capitulino {
21031da177e4SLinus Torvalds 	struct net_device *odev;
210439df232fSStephen Hemminger 	int err;
21051da177e4SLinus Torvalds 
21061da177e4SLinus Torvalds 	/* Clean old setups */
21071da177e4SLinus Torvalds 	if (pkt_dev->odev) {
21081da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
21091da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
21101da177e4SLinus Torvalds 	}
21111da177e4SLinus Torvalds 
21124e58a027SCong Wang 	odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname);
21131da177e4SLinus Torvalds 	if (!odev) {
2114f9467eaeSJoe Perches 		pr_err("no such netdevice: \"%s\"\n", ifname);
211539df232fSStephen Hemminger 		return -ENODEV;
21161da177e4SLinus Torvalds 	}
211739df232fSStephen Hemminger 
21181da177e4SLinus Torvalds 	if (odev->type != ARPHRD_ETHER) {
2119f9467eaeSJoe Perches 		pr_err("not an ethernet device: \"%s\"\n", ifname);
212039df232fSStephen Hemminger 		err = -EINVAL;
212139df232fSStephen Hemminger 	} else if (!netif_running(odev)) {
2122f9467eaeSJoe Perches 		pr_err("device is down: \"%s\"\n", ifname);
212339df232fSStephen Hemminger 		err = -ENETDOWN;
212439df232fSStephen Hemminger 	} else {
21251da177e4SLinus Torvalds 		pkt_dev->odev = odev;
212639df232fSStephen Hemminger 		return 0;
212739df232fSStephen Hemminger 	}
21281da177e4SLinus Torvalds 
21291da177e4SLinus Torvalds 	dev_put(odev);
213039df232fSStephen Hemminger 	return err;
21311da177e4SLinus Torvalds }
21321da177e4SLinus Torvalds 
21331da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev
21341da177e4SLinus Torvalds  * structure to have the right information to create/send packets
21351da177e4SLinus Torvalds  */
21361da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
21371da177e4SLinus Torvalds {
213864c00d81SAndrew Gallatin 	int ntxq;
213964c00d81SAndrew Gallatin 
21401da177e4SLinus Torvalds 	if (!pkt_dev->odev) {
2141f9467eaeSJoe Perches 		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
2142222f1806SLuiz Capitulino 		sprintf(pkt_dev->result,
2143222f1806SLuiz Capitulino 			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
21441da177e4SLinus Torvalds 		return;
21451da177e4SLinus Torvalds 	}
21461da177e4SLinus Torvalds 
214764c00d81SAndrew Gallatin 	/* make sure that we don't pick a non-existing transmit queue */
214864c00d81SAndrew Gallatin 	ntxq = pkt_dev->odev->real_num_tx_queues;
2149bfdbc0acSRobert Olsson 
215064c00d81SAndrew Gallatin 	if (ntxq <= pkt_dev->queue_map_min) {
2151294a0b7fSJoe Perches 		pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
215288271660SJesse Brandeburg 			pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
2153593f63b0SEric Dumazet 			pkt_dev->odevname);
215426e29eedSDan Carpenter 		pkt_dev->queue_map_min = (ntxq ?: 1) - 1;
215564c00d81SAndrew Gallatin 	}
215688271660SJesse Brandeburg 	if (pkt_dev->queue_map_max >= ntxq) {
2157294a0b7fSJoe Perches 		pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
215888271660SJesse Brandeburg 			pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
2159593f63b0SEric Dumazet 			pkt_dev->odevname);
216026e29eedSDan Carpenter 		pkt_dev->queue_map_max = (ntxq ?: 1) - 1;
216164c00d81SAndrew Gallatin 	}
216264c00d81SAndrew Gallatin 
21631da177e4SLinus Torvalds 	/* Default to the interface's mac if not explicitly set. */
21641da177e4SLinus Torvalds 
2165f404e9a6SKris Katterjohn 	if (is_zero_ether_addr(pkt_dev->src_mac))
21669ea08b12SJoe Perches 		ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr);
21671da177e4SLinus Torvalds 
21681da177e4SLinus Torvalds 	/* Set up Dest MAC */
21699ea08b12SJoe Perches 	ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac);
21701da177e4SLinus Torvalds 
21711da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
21724c139b8cSAmerigo Wang 		int i, set = 0, err = 1;
21734c139b8cSAmerigo Wang 		struct inet6_dev *idev;
21744c139b8cSAmerigo Wang 
217568bf9f0bSAmerigo Wang 		if (pkt_dev->min_pkt_size == 0) {
217668bf9f0bSAmerigo Wang 			pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr)
217768bf9f0bSAmerigo Wang 						+ sizeof(struct udphdr)
217868bf9f0bSAmerigo Wang 						+ sizeof(struct pktgen_hdr)
217968bf9f0bSAmerigo Wang 						+ pkt_dev->pkt_overhead;
218068bf9f0bSAmerigo Wang 		}
218168bf9f0bSAmerigo Wang 
2182df7e8e2eSEric Dumazet 		for (i = 0; i < sizeof(struct in6_addr); i++)
21831da177e4SLinus Torvalds 			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
21841da177e4SLinus Torvalds 				set = 1;
21851da177e4SLinus Torvalds 				break;
21861da177e4SLinus Torvalds 			}
21871da177e4SLinus Torvalds 
21881da177e4SLinus Torvalds 		if (!set) {
21891da177e4SLinus Torvalds 
21901da177e4SLinus Torvalds 			/*
21911da177e4SLinus Torvalds 			 * Use linklevel address if unconfigured.
21921da177e4SLinus Torvalds 			 *
21931da177e4SLinus Torvalds 			 * use ipv6_get_lladdr if/when it's get exported
21941da177e4SLinus Torvalds 			 */
21951da177e4SLinus Torvalds 
21968814c4b5SYOSHIFUJI Hideaki 			rcu_read_lock();
219763adc6fbSStephen Hemminger 			idev = __in6_dev_get(pkt_dev->odev);
219863adc6fbSStephen Hemminger 			if (idev) {
21991da177e4SLinus Torvalds 				struct inet6_ifaddr *ifp;
22001da177e4SLinus Torvalds 
22011da177e4SLinus Torvalds 				read_lock_bh(&idev->lock);
22024c139b8cSAmerigo Wang 				list_for_each_entry(ifp, &idev->addr_list, if_list) {
22034c139b8cSAmerigo Wang 					if ((ifp->scope & IFA_LINK) &&
2204f64f9e71SJoe Perches 					    !(ifp->flags & IFA_F_TENTATIVE)) {
22054e3fd7a0SAlexey Dobriyan 						pkt_dev->cur_in6_saddr = ifp->addr;
22061da177e4SLinus Torvalds 						err = 0;
22071da177e4SLinus Torvalds 						break;
22081da177e4SLinus Torvalds 					}
22091da177e4SLinus Torvalds 				}
22101da177e4SLinus Torvalds 				read_unlock_bh(&idev->lock);
22111da177e4SLinus Torvalds 			}
22128814c4b5SYOSHIFUJI Hideaki 			rcu_read_unlock();
2213222f1806SLuiz Capitulino 			if (err)
2214f9467eaeSJoe Perches 				pr_err("ERROR: IPv6 link address not available\n");
22151da177e4SLinus Torvalds 		}
2216222f1806SLuiz Capitulino 	} else {
221768bf9f0bSAmerigo Wang 		if (pkt_dev->min_pkt_size == 0) {
221868bf9f0bSAmerigo Wang 			pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr)
221968bf9f0bSAmerigo Wang 						+ sizeof(struct udphdr)
222068bf9f0bSAmerigo Wang 						+ sizeof(struct pktgen_hdr)
222168bf9f0bSAmerigo Wang 						+ pkt_dev->pkt_overhead;
222268bf9f0bSAmerigo Wang 		}
222368bf9f0bSAmerigo Wang 
22241da177e4SLinus Torvalds 		pkt_dev->saddr_min = 0;
22251da177e4SLinus Torvalds 		pkt_dev->saddr_max = 0;
22261da177e4SLinus Torvalds 		if (strlen(pkt_dev->src_min) == 0) {
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds 			struct in_device *in_dev;
22291da177e4SLinus Torvalds 
22301da177e4SLinus Torvalds 			rcu_read_lock();
2231e5ed6399SHerbert Xu 			in_dev = __in_dev_get_rcu(pkt_dev->odev);
22321da177e4SLinus Torvalds 			if (in_dev) {
22331da177e4SLinus Torvalds 				if (in_dev->ifa_list) {
2234222f1806SLuiz Capitulino 					pkt_dev->saddr_min =
2235222f1806SLuiz Capitulino 					    in_dev->ifa_list->ifa_address;
22361da177e4SLinus Torvalds 					pkt_dev->saddr_max = pkt_dev->saddr_min;
22371da177e4SLinus Torvalds 				}
22381da177e4SLinus Torvalds 			}
22391da177e4SLinus Torvalds 			rcu_read_unlock();
2240222f1806SLuiz Capitulino 		} else {
22411da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
22421da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
22431da177e4SLinus Torvalds 		}
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 		pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
22461da177e4SLinus Torvalds 		pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
22471da177e4SLinus Torvalds 	}
22481da177e4SLinus Torvalds 	/* Initialize current values. */
224968bf9f0bSAmerigo Wang 	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
225068bf9f0bSAmerigo Wang 	if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size)
225168bf9f0bSAmerigo Wang 		pkt_dev->max_pkt_size = pkt_dev->min_pkt_size;
225268bf9f0bSAmerigo Wang 
22531da177e4SLinus Torvalds 	pkt_dev->cur_dst_mac_offset = 0;
22541da177e4SLinus Torvalds 	pkt_dev->cur_src_mac_offset = 0;
22551da177e4SLinus Torvalds 	pkt_dev->cur_saddr = pkt_dev->saddr_min;
22561da177e4SLinus Torvalds 	pkt_dev->cur_daddr = pkt_dev->daddr_min;
22571da177e4SLinus Torvalds 	pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
22581da177e4SLinus Torvalds 	pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
22591da177e4SLinus Torvalds 	pkt_dev->nflows = 0;
22601da177e4SLinus Torvalds }
22611da177e4SLinus Torvalds 
22621da177e4SLinus Torvalds 
2263fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
2264fd29cf72SStephen Hemminger {
2265ef87979cSStephen Hemminger 	ktime_t start_time, end_time;
2266417bc4b8SEric Dumazet 	s64 remaining;
22672bc481cfSStephen Hemminger 	struct hrtimer_sleeper t;
2268fd29cf72SStephen Hemminger 
22692bc481cfSStephen Hemminger 	hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
22702bc481cfSStephen Hemminger 	hrtimer_set_expires(&t.timer, spin_until);
2271fd29cf72SStephen Hemminger 
227243d28b65SDaniel Turull 	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
2273bcf91bdbSGuenter Roeck 	if (remaining <= 0)
2274bcf91bdbSGuenter Roeck 		goto out;
22752bc481cfSStephen Hemminger 
2276398f382cSDaniel Borkmann 	start_time = ktime_get();
227733136d12SEric Dumazet 	if (remaining < 100000) {
227833136d12SEric Dumazet 		/* for small delays (<100us), just loop until limit is reached */
227933136d12SEric Dumazet 		do {
2280398f382cSDaniel Borkmann 			end_time = ktime_get();
2281398f382cSDaniel Borkmann 		} while (ktime_compare(end_time, spin_until) < 0);
228233136d12SEric Dumazet 	} else {
22832bc481cfSStephen Hemminger 		/* see do_nanosleep */
22842bc481cfSStephen Hemminger 		hrtimer_init_sleeper(&t, current);
22852bc481cfSStephen Hemminger 		do {
22862bc481cfSStephen Hemminger 			set_current_state(TASK_INTERRUPTIBLE);
22872bc481cfSStephen Hemminger 			hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
22882bc481cfSStephen Hemminger 
22892bc481cfSStephen Hemminger 			if (likely(t.task))
22901da177e4SLinus Torvalds 				schedule();
22911da177e4SLinus Torvalds 
22922bc481cfSStephen Hemminger 			hrtimer_cancel(&t.timer);
22932bc481cfSStephen Hemminger 		} while (t.task && pkt_dev->running && !signal_pending(current));
22942bc481cfSStephen Hemminger 		__set_current_state(TASK_RUNNING);
2295398f382cSDaniel Borkmann 		end_time = ktime_get();
229633136d12SEric Dumazet 	}
2297ef87979cSStephen Hemminger 
2298ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
2299bcf91bdbSGuenter Roeck out:
230007a0f0f0SDaniel Turull 	pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
2301bcf91bdbSGuenter Roeck 	destroy_hrtimer_on_stack(&t.timer);
23021da177e4SLinus Torvalds }
23031da177e4SLinus Torvalds 
230416dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
230516dab72fSJamal Hadi Salim {
230663d75463SPaolo Abeni 	pkt_dev->pkt_overhead = 0;
230716dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
230816dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
230916dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
231016dab72fSJamal Hadi Salim }
231116dab72fSJamal Hadi Salim 
2312648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
2313007a531bSJamal Hadi Salim {
2314648fda74SStephen Hemminger 	return !!(pkt_dev->flows[flow].flags & F_INIT);
2315007a531bSJamal Hadi Salim }
2316007a531bSJamal Hadi Salim 
2317007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev)
2318007a531bSJamal Hadi Salim {
2319007a531bSJamal Hadi Salim 	int flow = pkt_dev->curfl;
2320007a531bSJamal Hadi Salim 
2321007a531bSJamal Hadi Salim 	if (pkt_dev->flags & F_FLOW_SEQ) {
2322007a531bSJamal Hadi Salim 		if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
2323007a531bSJamal Hadi Salim 			/* reset time */
2324007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
23251211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
2326007a531bSJamal Hadi Salim 			pkt_dev->curfl += 1;
2327007a531bSJamal Hadi Salim 			if (pkt_dev->curfl >= pkt_dev->cflows)
2328007a531bSJamal Hadi Salim 				pkt_dev->curfl = 0; /*reset */
2329007a531bSJamal Hadi Salim 		}
2330007a531bSJamal Hadi Salim 	} else {
233133d7c5e5SAkinobu Mita 		flow = prandom_u32() % pkt_dev->cflows;
23321211a645SRobert Olsson 		pkt_dev->curfl = flow;
2333007a531bSJamal Hadi Salim 
23341211a645SRobert Olsson 		if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
2335007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
23361211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
23371211a645SRobert Olsson 		}
2338007a531bSJamal Hadi Salim 	}
2339007a531bSJamal Hadi Salim 
2340007a531bSJamal Hadi Salim 	return pkt_dev->curfl;
2341007a531bSJamal Hadi Salim }
2342007a531bSJamal Hadi Salim 
2343a553e4a6SJamal Hadi Salim 
2344a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2345a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else
2346a553e4a6SJamal Hadi Salim  * we go look for it ...
2347a553e4a6SJamal Hadi Salim */
2348bd55775cSJamal Hadi Salim #define DUMMY_MARK 0
2349fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
2350a553e4a6SJamal Hadi Salim {
2351a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[flow].x;
23524e58a027SCong Wang 	struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
2353a553e4a6SJamal Hadi Salim 	if (!x) {
2354c454997eSFan Du 
2355c454997eSFan Du 		if (pkt_dev->spi) {
2356c454997eSFan Du 			/* We need as quick as possible to find the right SA
2357c454997eSFan Du 			 * Searching with minimum criteria to archieve this.
2358c454997eSFan Du 			 */
2359c454997eSFan Du 			x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
2360c454997eSFan Du 		} else {
2361a553e4a6SJamal Hadi Salim 			/* slow path: we dont already have xfrm_state */
23624e58a027SCong Wang 			x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
23635447c5e4SAlexey Dobriyan 						(xfrm_address_t *)&pkt_dev->cur_daddr,
2364a553e4a6SJamal Hadi Salim 						(xfrm_address_t *)&pkt_dev->cur_saddr,
2365a553e4a6SJamal Hadi Salim 						AF_INET,
2366a553e4a6SJamal Hadi Salim 						pkt_dev->ipsmode,
2367a553e4a6SJamal Hadi Salim 						pkt_dev->ipsproto, 0);
2368c454997eSFan Du 		}
2369a553e4a6SJamal Hadi Salim 		if (x) {
2370a553e4a6SJamal Hadi Salim 			pkt_dev->flows[flow].x = x;
2371a553e4a6SJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
2372a553e4a6SJamal Hadi Salim 			pkt_dev->pkt_overhead += x->props.header_len;
2373a553e4a6SJamal Hadi Salim 		}
2374a553e4a6SJamal Hadi Salim 
2375a553e4a6SJamal Hadi Salim 	}
2376a553e4a6SJamal Hadi Salim }
2377a553e4a6SJamal Hadi Salim #endif
2378fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
2379fd2ea0a7SDavid S. Miller {
2380e6fce5b9SRobert Olsson 
2381e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
2382e6fce5b9SRobert Olsson 		pkt_dev->cur_queue_map = smp_processor_id();
2383e6fce5b9SRobert Olsson 
2384896a7cf8SEric Dumazet 	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
2385fd2ea0a7SDavid S. Miller 		__u16 t;
2386fd2ea0a7SDavid S. Miller 		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
238733d7c5e5SAkinobu Mita 			t = prandom_u32() %
2388fd2ea0a7SDavid S. Miller 				(pkt_dev->queue_map_max -
2389fd2ea0a7SDavid S. Miller 				 pkt_dev->queue_map_min + 1)
2390fd2ea0a7SDavid S. Miller 				+ pkt_dev->queue_map_min;
2391fd2ea0a7SDavid S. Miller 		} else {
2392fd2ea0a7SDavid S. Miller 			t = pkt_dev->cur_queue_map + 1;
2393fd2ea0a7SDavid S. Miller 			if (t > pkt_dev->queue_map_max)
2394fd2ea0a7SDavid S. Miller 				t = pkt_dev->queue_map_min;
2395fd2ea0a7SDavid S. Miller 		}
2396fd2ea0a7SDavid S. Miller 		pkt_dev->cur_queue_map = t;
2397fd2ea0a7SDavid S. Miller 	}
2398bfdbc0acSRobert Olsson 	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
2399fd2ea0a7SDavid S. Miller }
2400fd2ea0a7SDavid S. Miller 
24011da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values
24021da177e4SLinus Torvalds  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
24031da177e4SLinus Torvalds  */
2404222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev)
2405222f1806SLuiz Capitulino {
24061da177e4SLinus Torvalds 	__u32 imn;
24071da177e4SLinus Torvalds 	__u32 imx;
24081da177e4SLinus Torvalds 	int flow = 0;
24091da177e4SLinus Torvalds 
2410007a531bSJamal Hadi Salim 	if (pkt_dev->cflows)
2411007a531bSJamal Hadi Salim 		flow = f_pick(pkt_dev);
24121da177e4SLinus Torvalds 
24131da177e4SLinus Torvalds 	/*  Deal with source MAC */
24141da177e4SLinus Torvalds 	if (pkt_dev->src_mac_count > 1) {
24151da177e4SLinus Torvalds 		__u32 mc;
24161da177e4SLinus Torvalds 		__u32 tmp;
24171da177e4SLinus Torvalds 
24181da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACSRC_RND)
241933d7c5e5SAkinobu Mita 			mc = prandom_u32() % pkt_dev->src_mac_count;
24201da177e4SLinus Torvalds 		else {
24211da177e4SLinus Torvalds 			mc = pkt_dev->cur_src_mac_offset++;
2422ff2a79a5SRobert Olsson 			if (pkt_dev->cur_src_mac_offset >=
2423222f1806SLuiz Capitulino 			    pkt_dev->src_mac_count)
24241da177e4SLinus Torvalds 				pkt_dev->cur_src_mac_offset = 0;
24251da177e4SLinus Torvalds 		}
24261da177e4SLinus Torvalds 
24271da177e4SLinus Torvalds 		tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
24281da177e4SLinus Torvalds 		pkt_dev->hh[11] = tmp;
24291da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
24301da177e4SLinus Torvalds 		pkt_dev->hh[10] = tmp;
24311da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
24321da177e4SLinus Torvalds 		pkt_dev->hh[9] = tmp;
24331da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
24341da177e4SLinus Torvalds 		pkt_dev->hh[8] = tmp;
24351da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
24361da177e4SLinus Torvalds 		pkt_dev->hh[7] = tmp;
24371da177e4SLinus Torvalds 	}
24381da177e4SLinus Torvalds 
24391da177e4SLinus Torvalds 	/*  Deal with Destination MAC */
24401da177e4SLinus Torvalds 	if (pkt_dev->dst_mac_count > 1) {
24411da177e4SLinus Torvalds 		__u32 mc;
24421da177e4SLinus Torvalds 		__u32 tmp;
24431da177e4SLinus Torvalds 
24441da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACDST_RND)
244533d7c5e5SAkinobu Mita 			mc = prandom_u32() % pkt_dev->dst_mac_count;
24461da177e4SLinus Torvalds 
24471da177e4SLinus Torvalds 		else {
24481da177e4SLinus Torvalds 			mc = pkt_dev->cur_dst_mac_offset++;
2449ff2a79a5SRobert Olsson 			if (pkt_dev->cur_dst_mac_offset >=
2450222f1806SLuiz Capitulino 			    pkt_dev->dst_mac_count) {
24511da177e4SLinus Torvalds 				pkt_dev->cur_dst_mac_offset = 0;
24521da177e4SLinus Torvalds 			}
24531da177e4SLinus Torvalds 		}
24541da177e4SLinus Torvalds 
24551da177e4SLinus Torvalds 		tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
24561da177e4SLinus Torvalds 		pkt_dev->hh[5] = tmp;
24571da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
24581da177e4SLinus Torvalds 		pkt_dev->hh[4] = tmp;
24591da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
24601da177e4SLinus Torvalds 		pkt_dev->hh[3] = tmp;
24611da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
24621da177e4SLinus Torvalds 		pkt_dev->hh[2] = tmp;
24631da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
24641da177e4SLinus Torvalds 		pkt_dev->hh[1] = tmp;
24651da177e4SLinus Torvalds 	}
24661da177e4SLinus Torvalds 
2467ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND) {
246895c96174SEric Dumazet 		unsigned int i;
2469ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
2470ca6549afSSteven Whitehouse 			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
2471ca6549afSSteven Whitehouse 				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
247233d7c5e5SAkinobu Mita 					     ((__force __be32)prandom_u32() &
2473ca6549afSSteven Whitehouse 						      htonl(0x000fffff));
2474ca6549afSSteven Whitehouse 	}
2475ca6549afSSteven Whitehouse 
247634954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
247733d7c5e5SAkinobu Mita 		pkt_dev->vlan_id = prandom_u32() & (4096 - 1);
247834954ddcSFrancesco Fondelli 	}
247934954ddcSFrancesco Fondelli 
248034954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
248133d7c5e5SAkinobu Mita 		pkt_dev->svlan_id = prandom_u32() & (4096 - 1);
248234954ddcSFrancesco Fondelli 	}
248334954ddcSFrancesco Fondelli 
24841da177e4SLinus Torvalds 	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
24851da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPSRC_RND)
248633d7c5e5SAkinobu Mita 			pkt_dev->cur_udp_src = prandom_u32() %
24875fa6fc76SStephen Hemminger 				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
24885fa6fc76SStephen Hemminger 				+ pkt_dev->udp_src_min;
24891da177e4SLinus Torvalds 
24901da177e4SLinus Torvalds 		else {
24911da177e4SLinus Torvalds 			pkt_dev->cur_udp_src++;
24921da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
24931da177e4SLinus Torvalds 				pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
24941da177e4SLinus Torvalds 		}
24951da177e4SLinus Torvalds 	}
24961da177e4SLinus Torvalds 
24971da177e4SLinus Torvalds 	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
24981da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPDST_RND) {
249933d7c5e5SAkinobu Mita 			pkt_dev->cur_udp_dst = prandom_u32() %
25005fa6fc76SStephen Hemminger 				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
25015fa6fc76SStephen Hemminger 				+ pkt_dev->udp_dst_min;
2502222f1806SLuiz Capitulino 		} else {
25031da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst++;
25041da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
25051da177e4SLinus Torvalds 				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
25061da177e4SLinus Torvalds 		}
25071da177e4SLinus Torvalds 	}
25081da177e4SLinus Torvalds 
25091da177e4SLinus Torvalds 	if (!(pkt_dev->flags & F_IPV6)) {
25101da177e4SLinus Torvalds 
251163adc6fbSStephen Hemminger 		imn = ntohl(pkt_dev->saddr_min);
251263adc6fbSStephen Hemminger 		imx = ntohl(pkt_dev->saddr_max);
251363adc6fbSStephen Hemminger 		if (imn < imx) {
25141da177e4SLinus Torvalds 			__u32 t;
25151da177e4SLinus Torvalds 			if (pkt_dev->flags & F_IPSRC_RND)
251633d7c5e5SAkinobu Mita 				t = prandom_u32() % (imx - imn) + imn;
25171da177e4SLinus Torvalds 			else {
25181da177e4SLinus Torvalds 				t = ntohl(pkt_dev->cur_saddr);
25191da177e4SLinus Torvalds 				t++;
252063adc6fbSStephen Hemminger 				if (t > imx)
25211da177e4SLinus Torvalds 					t = imn;
252263adc6fbSStephen Hemminger 
25231da177e4SLinus Torvalds 			}
25241da177e4SLinus Torvalds 			pkt_dev->cur_saddr = htonl(t);
25251da177e4SLinus Torvalds 		}
25261da177e4SLinus Torvalds 
2527007a531bSJamal Hadi Salim 		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
25281da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
25291da177e4SLinus Torvalds 		} else {
2530252e3346SAl Viro 			imn = ntohl(pkt_dev->daddr_min);
2531252e3346SAl Viro 			imx = ntohl(pkt_dev->daddr_max);
2532252e3346SAl Viro 			if (imn < imx) {
25331da177e4SLinus Torvalds 				__u32 t;
2534252e3346SAl Viro 				__be32 s;
25351da177e4SLinus Torvalds 				if (pkt_dev->flags & F_IPDST_RND) {
25361da177e4SLinus Torvalds 
253770e3ba72SAkinobu Mita 					do {
253833d7c5e5SAkinobu Mita 						t = prandom_u32() %
253933d7c5e5SAkinobu Mita 							(imx - imn) + imn;
2540252e3346SAl Viro 						s = htonl(t);
254170e3ba72SAkinobu Mita 					} while (ipv4_is_loopback(s) ||
254270e3ba72SAkinobu Mita 						ipv4_is_multicast(s) ||
254370e3ba72SAkinobu Mita 						ipv4_is_lbcast(s) ||
254470e3ba72SAkinobu Mita 						ipv4_is_zeronet(s) ||
254570e3ba72SAkinobu Mita 						ipv4_is_local_multicast(s));
2546252e3346SAl Viro 					pkt_dev->cur_daddr = s;
2547252e3346SAl Viro 				} else {
25481da177e4SLinus Torvalds 					t = ntohl(pkt_dev->cur_daddr);
25491da177e4SLinus Torvalds 					t++;
25501da177e4SLinus Torvalds 					if (t > imx) {
25511da177e4SLinus Torvalds 						t = imn;
25521da177e4SLinus Torvalds 					}
25531da177e4SLinus Torvalds 					pkt_dev->cur_daddr = htonl(t);
25541da177e4SLinus Torvalds 				}
25551da177e4SLinus Torvalds 			}
25561da177e4SLinus Torvalds 			if (pkt_dev->cflows) {
2557007a531bSJamal Hadi Salim 				pkt_dev->flows[flow].flags |= F_INIT;
2558222f1806SLuiz Capitulino 				pkt_dev->flows[flow].cur_daddr =
2559222f1806SLuiz Capitulino 				    pkt_dev->cur_daddr;
2560a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2561*6f107c74SDmitry Safonov 				if (pkt_dev->flags & F_IPSEC)
2562a553e4a6SJamal Hadi Salim 					get_ipsec_sa(pkt_dev, flow);
2563a553e4a6SJamal Hadi Salim #endif
25641da177e4SLinus Torvalds 				pkt_dev->nflows++;
25651da177e4SLinus Torvalds 			}
25661da177e4SLinus Torvalds 		}
2567222f1806SLuiz Capitulino 	} else {		/* IPV6 * */
2568222f1806SLuiz Capitulino 
256906e30411SJoe Perches 		if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) {
25701da177e4SLinus Torvalds 			int i;
25711da177e4SLinus Torvalds 
25721da177e4SLinus Torvalds 			/* Only random destinations yet */
25731da177e4SLinus Torvalds 
25741da177e4SLinus Torvalds 			for (i = 0; i < 4; i++) {
25751da177e4SLinus Torvalds 				pkt_dev->cur_in6_daddr.s6_addr32[i] =
257633d7c5e5SAkinobu Mita 				    (((__force __be32)prandom_u32() |
25771da177e4SLinus Torvalds 				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
25781da177e4SLinus Torvalds 				     pkt_dev->max_in6_daddr.s6_addr32[i]);
25791da177e4SLinus Torvalds 			}
25801da177e4SLinus Torvalds 		}
25811da177e4SLinus Torvalds 	}
25821da177e4SLinus Torvalds 
25831da177e4SLinus Torvalds 	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
25841da177e4SLinus Torvalds 		__u32 t;
25851da177e4SLinus Torvalds 		if (pkt_dev->flags & F_TXSIZE_RND) {
258633d7c5e5SAkinobu Mita 			t = prandom_u32() %
25875fa6fc76SStephen Hemminger 				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
25885fa6fc76SStephen Hemminger 				+ pkt_dev->min_pkt_size;
2589222f1806SLuiz Capitulino 		} else {
25901da177e4SLinus Torvalds 			t = pkt_dev->cur_pkt_size + 1;
25911da177e4SLinus Torvalds 			if (t > pkt_dev->max_pkt_size)
25921da177e4SLinus Torvalds 				t = pkt_dev->min_pkt_size;
25931da177e4SLinus Torvalds 		}
25941da177e4SLinus Torvalds 		pkt_dev->cur_pkt_size = t;
25951da177e4SLinus Torvalds 	}
25961da177e4SLinus Torvalds 
2597fd2ea0a7SDavid S. Miller 	set_cur_queue_map(pkt_dev);
259845b270f8SRobert Olsson 
25991da177e4SLinus Torvalds 	pkt_dev->flows[flow].count++;
26001da177e4SLinus Torvalds }
26011da177e4SLinus Torvalds 
2602a553e4a6SJamal Hadi Salim 
2603a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
26045537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
2605cf93d47eSFan Du 
2606cf93d47eSFan Du 	[RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
2607cf93d47eSFan Du };
2608cf93d47eSFan Du 
2609a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
2610a553e4a6SJamal Hadi Salim {
2611a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2612a553e4a6SJamal Hadi Salim 	int err = 0;
26136de9ace4SFan Du 	struct net *net = dev_net(pkt_dev->odev);
2614a553e4a6SJamal Hadi Salim 
2615a553e4a6SJamal Hadi Salim 	if (!x)
2616a553e4a6SJamal Hadi Salim 		return 0;
2617a553e4a6SJamal Hadi Salim 	/* XXX: we dont support tunnel mode for now until
2618a553e4a6SJamal Hadi Salim 	 * we resolve the dst issue */
2619cf93d47eSFan Du 	if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
2620a553e4a6SJamal Hadi Salim 		return 0;
2621a553e4a6SJamal Hadi Salim 
2622cf93d47eSFan Du 	/* But when user specify an valid SPI, transformation
2623cf93d47eSFan Du 	 * supports both transport/tunnel mode + ESP/AH type.
2624cf93d47eSFan Du 	 */
2625cf93d47eSFan Du 	if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
2626b6ca8bd5SDavid Miller 		skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF;
2627cf93d47eSFan Du 
2628cf93d47eSFan Du 	rcu_read_lock_bh();
262913996378SHerbert Xu 	err = x->outer_mode->output(x, skb);
2630cf93d47eSFan Du 	rcu_read_unlock_bh();
26316de9ace4SFan Du 	if (err) {
26326de9ace4SFan Du 		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
2633a553e4a6SJamal Hadi Salim 		goto error;
26346de9ace4SFan Du 	}
2635a553e4a6SJamal Hadi Salim 	err = x->type->output(x, skb);
26366de9ace4SFan Du 	if (err) {
26376de9ace4SFan Du 		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
2638a553e4a6SJamal Hadi Salim 		goto error;
26396de9ace4SFan Du 	}
26400af0a413SFan Du 	spin_lock_bh(&x->lock);
2641a553e4a6SJamal Hadi Salim 	x->curlft.bytes += skb->len;
2642a553e4a6SJamal Hadi Salim 	x->curlft.packets++;
26430af0a413SFan Du 	spin_unlock_bh(&x->lock);
2644a553e4a6SJamal Hadi Salim error:
2645a553e4a6SJamal Hadi Salim 	return err;
2646a553e4a6SJamal Hadi Salim }
2647a553e4a6SJamal Hadi Salim 
2648475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev)
2649a553e4a6SJamal Hadi Salim {
2650a553e4a6SJamal Hadi Salim 	if (pkt_dev->cflows) {
2651a553e4a6SJamal Hadi Salim 		/* let go of the SAs if we have them */
2652d6182223SPaul Gortmaker 		int i;
2653d6182223SPaul Gortmaker 		for (i = 0; i < pkt_dev->cflows; i++) {
2654a553e4a6SJamal Hadi Salim 			struct xfrm_state *x = pkt_dev->flows[i].x;
2655a553e4a6SJamal Hadi Salim 			if (x) {
2656a553e4a6SJamal Hadi Salim 				xfrm_state_put(x);
2657a553e4a6SJamal Hadi Salim 				pkt_dev->flows[i].x = NULL;
2658a553e4a6SJamal Hadi Salim 			}
2659a553e4a6SJamal Hadi Salim 		}
2660a553e4a6SJamal Hadi Salim 	}
2661a553e4a6SJamal Hadi Salim }
2662a553e4a6SJamal Hadi Salim 
2663475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev,
2664a553e4a6SJamal Hadi Salim 			      struct sk_buff *skb, __be16 protocol)
2665a553e4a6SJamal Hadi Salim {
2666*6f107c74SDmitry Safonov 	if (pkt_dev->flags & F_IPSEC) {
2667a553e4a6SJamal Hadi Salim 		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2668a553e4a6SJamal Hadi Salim 		int nhead = 0;
2669a553e4a6SJamal Hadi Salim 		if (x) {
2670d4969581SEric Dumazet 			struct ethhdr *eth;
26713868204dSfan.du 			struct iphdr *iph;
2672d4969581SEric Dumazet 			int ret;
26733868204dSfan.du 
2674a553e4a6SJamal Hadi Salim 			nhead = x->props.header_len - skb_headroom(skb);
2675a553e4a6SJamal Hadi Salim 			if (nhead > 0) {
2676a553e4a6SJamal Hadi Salim 				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
2677a553e4a6SJamal Hadi Salim 				if (ret < 0) {
2678f9467eaeSJoe Perches 					pr_err("Error expanding ipsec packet %d\n",
2679f9467eaeSJoe Perches 					       ret);
2680b4bb4ac8SIlpo Järvinen 					goto err;
2681a553e4a6SJamal Hadi Salim 				}
2682a553e4a6SJamal Hadi Salim 			}
2683a553e4a6SJamal Hadi Salim 
2684a553e4a6SJamal Hadi Salim 			/* ipsec is not expecting ll header */
2685a553e4a6SJamal Hadi Salim 			skb_pull(skb, ETH_HLEN);
2686a553e4a6SJamal Hadi Salim 			ret = pktgen_output_ipsec(skb, pkt_dev);
2687a553e4a6SJamal Hadi Salim 			if (ret) {
2688f9467eaeSJoe Perches 				pr_err("Error creating ipsec packet %d\n", ret);
2689b4bb4ac8SIlpo Järvinen 				goto err;
2690a553e4a6SJamal Hadi Salim 			}
2691a553e4a6SJamal Hadi Salim 			/* restore ll */
2692d58ff351SJohannes Berg 			eth = skb_push(skb, ETH_HLEN);
2693d4969581SEric Dumazet 			memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN);
2694d4969581SEric Dumazet 			eth->h_proto = protocol;
26953868204dSfan.du 
26963868204dSfan.du 			/* Update IPv4 header len as well as checksum value */
26973868204dSfan.du 			iph = ip_hdr(skb);
26983868204dSfan.du 			iph->tot_len = htons(skb->len - ETH_HLEN);
26993868204dSfan.du 			ip_send_check(iph);
2700a553e4a6SJamal Hadi Salim 		}
2701a553e4a6SJamal Hadi Salim 	}
2702a553e4a6SJamal Hadi Salim 	return 1;
2703b4bb4ac8SIlpo Järvinen err:
2704b4bb4ac8SIlpo Järvinen 	kfree_skb(skb);
2705b4bb4ac8SIlpo Järvinen 	return 0;
2706a553e4a6SJamal Hadi Salim }
2707a553e4a6SJamal Hadi Salim #endif
2708a553e4a6SJamal Hadi Salim 
2709ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
2710ca6549afSSteven Whitehouse {
271195c96174SEric Dumazet 	unsigned int i;
271263adc6fbSStephen Hemminger 	for (i = 0; i < pkt_dev->nr_labels; i++)
2713ca6549afSSteven Whitehouse 		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
271463adc6fbSStephen Hemminger 
2715ca6549afSSteven Whitehouse 	mpls--;
2716ca6549afSSteven Whitehouse 	*mpls |= MPLS_STACK_BOTTOM;
2717ca6549afSSteven Whitehouse }
2718ca6549afSSteven Whitehouse 
27190f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi,
27200f37c605SAl Viro 			       unsigned int prio)
27210f37c605SAl Viro {
27220f37c605SAl Viro 	return htons(id | (cfi << 12) | (prio << 13));
27230f37c605SAl Viro }
27240f37c605SAl Viro 
272526ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
272626ad7879SEric Dumazet 				int datalen)
272726ad7879SEric Dumazet {
27287f5d3f27SArnd Bergmann 	struct timespec64 timestamp;
272926ad7879SEric Dumazet 	struct pktgen_hdr *pgh;
273026ad7879SEric Dumazet 
27314df864c1SJohannes Berg 	pgh = skb_put(skb, sizeof(*pgh));
273226ad7879SEric Dumazet 	datalen -= sizeof(*pgh);
273326ad7879SEric Dumazet 
273426ad7879SEric Dumazet 	if (pkt_dev->nfrags <= 0) {
2735b080db58SJohannes Berg 		skb_put_zero(skb, datalen);
273626ad7879SEric Dumazet 	} else {
273726ad7879SEric Dumazet 		int frags = pkt_dev->nfrags;
273826ad7879SEric Dumazet 		int i, len;
27397d36a991Samit salecha 		int frag_len;
274026ad7879SEric Dumazet 
274126ad7879SEric Dumazet 
274226ad7879SEric Dumazet 		if (frags > MAX_SKB_FRAGS)
274326ad7879SEric Dumazet 			frags = MAX_SKB_FRAGS;
274426ad7879SEric Dumazet 		len = datalen - frags * PAGE_SIZE;
274526ad7879SEric Dumazet 		if (len > 0) {
2746b080db58SJohannes Berg 			skb_put_zero(skb, len);
274726ad7879SEric Dumazet 			datalen = frags * PAGE_SIZE;
274826ad7879SEric Dumazet 		}
274926ad7879SEric Dumazet 
275026ad7879SEric Dumazet 		i = 0;
27517d36a991Samit salecha 		frag_len = (datalen/frags) < PAGE_SIZE ?
27527d36a991Samit salecha 			   (datalen/frags) : PAGE_SIZE;
275326ad7879SEric Dumazet 		while (datalen > 0) {
275426ad7879SEric Dumazet 			if (unlikely(!pkt_dev->page)) {
275526ad7879SEric Dumazet 				int node = numa_node_id();
275626ad7879SEric Dumazet 
275726ad7879SEric Dumazet 				if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
275826ad7879SEric Dumazet 					node = pkt_dev->node;
275926ad7879SEric Dumazet 				pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
276026ad7879SEric Dumazet 				if (!pkt_dev->page)
276126ad7879SEric Dumazet 					break;
276226ad7879SEric Dumazet 			}
2763a0bec1cdSIan Campbell 			get_page(pkt_dev->page);
2764ea2ab693SIan Campbell 			skb_frag_set_page(skb, i, pkt_dev->page);
276526ad7879SEric Dumazet 			skb_shinfo(skb)->frags[i].page_offset = 0;
27667d36a991Samit salecha 			/*last fragment, fill rest of data*/
27677d36a991Samit salecha 			if (i == (frags - 1))
27689e903e08SEric Dumazet 				skb_frag_size_set(&skb_shinfo(skb)->frags[i],
27699e903e08SEric Dumazet 				    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE));
27707d36a991Samit salecha 			else
27719e903e08SEric Dumazet 				skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len);
27729e903e08SEric Dumazet 			datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
27739e903e08SEric Dumazet 			skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
27749e903e08SEric Dumazet 			skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
277526ad7879SEric Dumazet 			i++;
277626ad7879SEric Dumazet 			skb_shinfo(skb)->nr_frags = i;
277726ad7879SEric Dumazet 		}
277826ad7879SEric Dumazet 	}
277926ad7879SEric Dumazet 
278026ad7879SEric Dumazet 	/* Stamp the time, and sequence number,
278126ad7879SEric Dumazet 	 * convert them to network byte order
278226ad7879SEric Dumazet 	 */
278326ad7879SEric Dumazet 	pgh->pgh_magic = htonl(PKTGEN_MAGIC);
278426ad7879SEric Dumazet 	pgh->seq_num = htonl(pkt_dev->seq_num);
278526ad7879SEric Dumazet 
2786afb84b62SJesper Dangaard Brouer 	if (pkt_dev->flags & F_NO_TIMESTAMP) {
2787afb84b62SJesper Dangaard Brouer 		pgh->tv_sec = 0;
2788afb84b62SJesper Dangaard Brouer 		pgh->tv_usec = 0;
2789afb84b62SJesper Dangaard Brouer 	} else {
27907f5d3f27SArnd Bergmann 		/*
27917f5d3f27SArnd Bergmann 		 * pgh->tv_sec wraps in y2106 when interpreted as unsigned
27927f5d3f27SArnd Bergmann 		 * as done by wireshark, or y2038 when interpreted as signed.
27937f5d3f27SArnd Bergmann 		 * This is probably harmless, but if anyone wants to improve
27947f5d3f27SArnd Bergmann 		 * it, we could introduce a variant that puts 64-bit nanoseconds
27957f5d3f27SArnd Bergmann 		 * into the respective header bytes.
27967f5d3f27SArnd Bergmann 		 * This would also be slightly faster to read.
27977f5d3f27SArnd Bergmann 		 */
27987f5d3f27SArnd Bergmann 		ktime_get_real_ts64(&timestamp);
279926ad7879SEric Dumazet 		pgh->tv_sec = htonl(timestamp.tv_sec);
28007f5d3f27SArnd Bergmann 		pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC);
280126ad7879SEric Dumazet 	}
2802afb84b62SJesper Dangaard Brouer }
280326ad7879SEric Dumazet 
28047a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
280563d75463SPaolo Abeni 					struct pktgen_dev *pkt_dev)
28067a6e288dSDaniel Borkmann {
280763d75463SPaolo Abeni 	unsigned int extralen = LL_RESERVED_SPACE(dev);
28087a6e288dSDaniel Borkmann 	struct sk_buff *skb = NULL;
280963d75463SPaolo Abeni 	unsigned int size;
28107a6e288dSDaniel Borkmann 
281163d75463SPaolo Abeni 	size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead;
28127a6e288dSDaniel Borkmann 	if (pkt_dev->flags & F_NODE) {
28137a6e288dSDaniel Borkmann 		int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();
28147a6e288dSDaniel Borkmann 
28157a6e288dSDaniel Borkmann 		skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node);
28167a6e288dSDaniel Borkmann 		if (likely(skb)) {
28177a6e288dSDaniel Borkmann 			skb_reserve(skb, NET_SKB_PAD);
28187a6e288dSDaniel Borkmann 			skb->dev = dev;
28197a6e288dSDaniel Borkmann 		}
28207a6e288dSDaniel Borkmann 	} else {
28217a6e288dSDaniel Borkmann 		 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
28227a6e288dSDaniel Borkmann 	}
28233de03596SJohn Fastabend 
282463d75463SPaolo Abeni 	/* the caller pre-fetches from skb->data and reserves for the mac hdr */
28253de03596SJohn Fastabend 	if (likely(skb))
282663d75463SPaolo Abeni 		skb_reserve(skb, extralen - 16);
28277a6e288dSDaniel Borkmann 
28287a6e288dSDaniel Borkmann 	return skb;
28297a6e288dSDaniel Borkmann }
28307a6e288dSDaniel Borkmann 
28311da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
28321da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
28331da177e4SLinus Torvalds {
28341da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
28351da177e4SLinus Torvalds 	__u8 *eth;
28361da177e4SLinus Torvalds 	struct udphdr *udph;
28371da177e4SLinus Torvalds 	int datalen, iplen;
28381da177e4SLinus Torvalds 	struct iphdr *iph;
2839d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IP);
2840ca6549afSSteven Whitehouse 	__be32 *mpls;
284134954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
284234954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
284334954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
284434954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2845fd2ea0a7SDavid S. Miller 	u16 queue_map;
2846ca6549afSSteven Whitehouse 
2847ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2848d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
28491da177e4SLinus Torvalds 
285034954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2851d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
285234954ddcSFrancesco Fondelli 
285364053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
285464053beeSRobert Olsson 	 * fields.
285564053beeSRobert Olsson 	 */
285664053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
2857eb589063SJunchang Wang 	queue_map = pkt_dev->cur_queue_map;
285864053beeSRobert Olsson 
285963d75463SPaolo Abeni 	skb = pktgen_alloc_skb(odev, pkt_dev);
28601da177e4SLinus Torvalds 	if (!skb) {
28611da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
28621da177e4SLinus Torvalds 		return NULL;
28631da177e4SLinus Torvalds 	}
28641da177e4SLinus Torvalds 
28657a6e288dSDaniel Borkmann 	prefetchw(skb->data);
286663d75463SPaolo Abeni 	skb_reserve(skb, 16);
28671da177e4SLinus Torvalds 
28681da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
2869d58ff351SJohannes Berg 	eth = skb_push(skb, 14);
28704df864c1SJohannes Berg 	mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32));
2871ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2872ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
287334954ddcSFrancesco Fondelli 
287434954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
287534954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
28764df864c1SJohannes Berg 			svlan_tci = skb_put(skb, sizeof(__be16));
28770f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
28780f37c605SAl Viro 					       pkt_dev->svlan_cfi,
28790f37c605SAl Viro 					       pkt_dev->svlan_p);
28804df864c1SJohannes Berg 			svlan_encapsulated_proto = skb_put(skb,
28814df864c1SJohannes Berg 							   sizeof(__be16));
2882d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
288334954ddcSFrancesco Fondelli 		}
28844df864c1SJohannes Berg 		vlan_tci = skb_put(skb, sizeof(__be16));
28850f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
28860f37c605SAl Viro 				      pkt_dev->vlan_cfi,
28870f37c605SAl Viro 				      pkt_dev->vlan_p);
28884df864c1SJohannes Berg 		vlan_encapsulated_proto = skb_put(skb, sizeof(__be16));
2889d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IP);
289034954ddcSFrancesco Fondelli 	}
289134954ddcSFrancesco Fondelli 
2892c145aeb3SZhang Shengju 	skb_reset_mac_header(skb);
2893525cebedSThomas Graf 	skb_set_network_header(skb, skb->len);
28944df864c1SJohannes Berg 	iph = skb_put(skb, sizeof(struct iphdr));
2895525cebedSThomas Graf 
2896525cebedSThomas Graf 	skb_set_transport_header(skb, skb->len);
28974df864c1SJohannes Berg 	udph = skb_put(skb, sizeof(struct udphdr));
2898fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
28999e50e3acSJohn Fastabend 	skb->priority = pkt_dev->skb_priority;
29009e50e3acSJohn Fastabend 
29011da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2902252e3346SAl Viro 	*(__be16 *) & eth[12] = protocol;
29031da177e4SLinus Torvalds 
2904ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2905ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
290616dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
29076af773e7SNishank Trivedi 	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr))
29081da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
29091da177e4SLinus Torvalds 
29101da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
29111da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
29121da177e4SLinus Torvalds 	udph->len = htons(datalen + 8);	/* DATA + udphdr */
2913c26bf4a5SThomas Graf 	udph->check = 0;
29141da177e4SLinus Torvalds 
29151da177e4SLinus Torvalds 	iph->ihl = 5;
29161da177e4SLinus Torvalds 	iph->version = 4;
29171da177e4SLinus Torvalds 	iph->ttl = 32;
29181ca7768cSFrancesco Fondelli 	iph->tos = pkt_dev->tos;
29191da177e4SLinus Torvalds 	iph->protocol = IPPROTO_UDP;	/* UDP */
29201da177e4SLinus Torvalds 	iph->saddr = pkt_dev->cur_saddr;
29211da177e4SLinus Torvalds 	iph->daddr = pkt_dev->cur_daddr;
292266ed1e5eSEric Dumazet 	iph->id = htons(pkt_dev->ip_id);
292366ed1e5eSEric Dumazet 	pkt_dev->ip_id++;
29241da177e4SLinus Torvalds 	iph->frag_off = 0;
29251da177e4SLinus Torvalds 	iplen = 20 + 8 + datalen;
29261da177e4SLinus Torvalds 	iph->tot_len = htons(iplen);
292703c633e7SThomas Graf 	ip_send_check(iph);
2928ca6549afSSteven Whitehouse 	skb->protocol = protocol;
29291da177e4SLinus Torvalds 	skb->dev = odev;
29301da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
2931c26bf4a5SThomas Graf 
29327744b5f3SSabrina Dubroca 	pktgen_finalize_skb(pkt_dev, skb, datalen);
29337744b5f3SSabrina Dubroca 
2934c26bf4a5SThomas Graf 	if (!(pkt_dev->flags & F_UDPCSUM)) {
2935c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_NONE;
2936c8cd0989STom Herbert 	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) {
2937c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_PARTIAL;
2938c26bf4a5SThomas Graf 		skb->csum = 0;
29397744b5f3SSabrina Dubroca 		udp4_hwcsum(skb, iph->saddr, iph->daddr);
2940c26bf4a5SThomas Graf 	} else {
29417744b5f3SSabrina Dubroca 		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0);
2942c26bf4a5SThomas Graf 
2943c26bf4a5SThomas Graf 		/* add protocol-dependent pseudo-header */
29447744b5f3SSabrina Dubroca 		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
2945c26bf4a5SThomas Graf 						datalen + 8, IPPROTO_UDP, csum);
2946c26bf4a5SThomas Graf 
2947c26bf4a5SThomas Graf 		if (udph->check == 0)
2948c26bf4a5SThomas Graf 			udph->check = CSUM_MANGLED_0;
2949c26bf4a5SThomas Graf 	}
2950c26bf4a5SThomas Graf 
2951a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2952a553e4a6SJamal Hadi Salim 	if (!process_ipsec(pkt_dev, skb, protocol))
2953a553e4a6SJamal Hadi Salim 		return NULL;
2954a553e4a6SJamal Hadi Salim #endif
2955a553e4a6SJamal Hadi Salim 
29561da177e4SLinus Torvalds 	return skb;
29571da177e4SLinus Torvalds }
29581da177e4SLinus Torvalds 
29591da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
29601da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
29611da177e4SLinus Torvalds {
29621da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
29631da177e4SLinus Torvalds 	__u8 *eth;
29641da177e4SLinus Torvalds 	struct udphdr *udph;
2965c26bf4a5SThomas Graf 	int datalen, udplen;
29661da177e4SLinus Torvalds 	struct ipv6hdr *iph;
2967d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IPV6);
2968ca6549afSSteven Whitehouse 	__be32 *mpls;
296934954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
297034954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
297134954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
297234954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2973fd2ea0a7SDavid S. Miller 	u16 queue_map;
2974ca6549afSSteven Whitehouse 
2975ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2976d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
29771da177e4SLinus Torvalds 
297834954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2979d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
298034954ddcSFrancesco Fondelli 
298164053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
298264053beeSRobert Olsson 	 * fields.
298364053beeSRobert Olsson 	 */
298464053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
2985eb589063SJunchang Wang 	queue_map = pkt_dev->cur_queue_map;
298664053beeSRobert Olsson 
298763d75463SPaolo Abeni 	skb = pktgen_alloc_skb(odev, pkt_dev);
29881da177e4SLinus Torvalds 	if (!skb) {
29891da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
29901da177e4SLinus Torvalds 		return NULL;
29911da177e4SLinus Torvalds 	}
29921da177e4SLinus Torvalds 
29937a6e288dSDaniel Borkmann 	prefetchw(skb->data);
29941da177e4SLinus Torvalds 	skb_reserve(skb, 16);
29951da177e4SLinus Torvalds 
29961da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
2997d58ff351SJohannes Berg 	eth = skb_push(skb, 14);
29984df864c1SJohannes Berg 	mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32));
2999ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
3000ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
300134954ddcSFrancesco Fondelli 
300234954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
300334954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
30044df864c1SJohannes Berg 			svlan_tci = skb_put(skb, sizeof(__be16));
30050f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
30060f37c605SAl Viro 					       pkt_dev->svlan_cfi,
30070f37c605SAl Viro 					       pkt_dev->svlan_p);
30084df864c1SJohannes Berg 			svlan_encapsulated_proto = skb_put(skb,
30094df864c1SJohannes Berg 							   sizeof(__be16));
3010d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
301134954ddcSFrancesco Fondelli 		}
30124df864c1SJohannes Berg 		vlan_tci = skb_put(skb, sizeof(__be16));
30130f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
30140f37c605SAl Viro 				      pkt_dev->vlan_cfi,
30150f37c605SAl Viro 				      pkt_dev->vlan_p);
30164df864c1SJohannes Berg 		vlan_encapsulated_proto = skb_put(skb, sizeof(__be16));
3017d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
301834954ddcSFrancesco Fondelli 	}
301934954ddcSFrancesco Fondelli 
3020c145aeb3SZhang Shengju 	skb_reset_mac_header(skb);
3021525cebedSThomas Graf 	skb_set_network_header(skb, skb->len);
30224df864c1SJohannes Berg 	iph = skb_put(skb, sizeof(struct ipv6hdr));
3023525cebedSThomas Graf 
3024525cebedSThomas Graf 	skb_set_transport_header(skb, skb->len);
30254df864c1SJohannes Berg 	udph = skb_put(skb, sizeof(struct udphdr));
3026fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
30279e50e3acSJohn Fastabend 	skb->priority = pkt_dev->skb_priority;
30281da177e4SLinus Torvalds 
30291da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
3030252e3346SAl Viro 	*(__be16 *) &eth[12] = protocol;
30311da177e4SLinus Torvalds 
3032ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
3033ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 -
3034ca6549afSSteven Whitehouse 		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
303516dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
30361da177e4SLinus Torvalds 
30375aa8b572SAmerigo Wang 	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) {
30381da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
3039e87cc472SJoe Perches 		net_info_ratelimited("increased datalen to %d\n", datalen);
30401da177e4SLinus Torvalds 	}
30411da177e4SLinus Torvalds 
3042c26bf4a5SThomas Graf 	udplen = datalen + sizeof(struct udphdr);
30431da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
30441da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
3045c26bf4a5SThomas Graf 	udph->len = htons(udplen);
3046c26bf4a5SThomas Graf 	udph->check = 0;
30471da177e4SLinus Torvalds 
3048d5f1ce9aSStephen Hemminger 	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
30491da177e4SLinus Torvalds 
30501ca7768cSFrancesco Fondelli 	if (pkt_dev->traffic_class) {
30511ca7768cSFrancesco Fondelli 		/* Version + traffic class + flow (0) */
3052252e3346SAl Viro 		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
30531ca7768cSFrancesco Fondelli 	}
30541ca7768cSFrancesco Fondelli 
30551da177e4SLinus Torvalds 	iph->hop_limit = 32;
30561da177e4SLinus Torvalds 
3057c26bf4a5SThomas Graf 	iph->payload_len = htons(udplen);
30581da177e4SLinus Torvalds 	iph->nexthdr = IPPROTO_UDP;
30591da177e4SLinus Torvalds 
30604e3fd7a0SAlexey Dobriyan 	iph->daddr = pkt_dev->cur_in6_daddr;
30614e3fd7a0SAlexey Dobriyan 	iph->saddr = pkt_dev->cur_in6_saddr;
30621da177e4SLinus Torvalds 
3063ca6549afSSteven Whitehouse 	skb->protocol = protocol;
30641da177e4SLinus Torvalds 	skb->dev = odev;
30651da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
30661da177e4SLinus Torvalds 
30677744b5f3SSabrina Dubroca 	pktgen_finalize_skb(pkt_dev, skb, datalen);
30687744b5f3SSabrina Dubroca 
3069c26bf4a5SThomas Graf 	if (!(pkt_dev->flags & F_UDPCSUM)) {
3070c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_NONE;
3071c8cd0989STom Herbert 	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) {
3072c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_PARTIAL;
3073c26bf4a5SThomas Graf 		skb->csum_start = skb_transport_header(skb) - skb->head;
3074c26bf4a5SThomas Graf 		skb->csum_offset = offsetof(struct udphdr, check);
3075c26bf4a5SThomas Graf 		udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
3076c26bf4a5SThomas Graf 	} else {
30777744b5f3SSabrina Dubroca 		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0);
3078c26bf4a5SThomas Graf 
3079c26bf4a5SThomas Graf 		/* add protocol-dependent pseudo-header */
3080c26bf4a5SThomas Graf 		udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);
3081c26bf4a5SThomas Graf 
3082c26bf4a5SThomas Graf 		if (udph->check == 0)
3083c26bf4a5SThomas Graf 			udph->check = CSUM_MANGLED_0;
3084c26bf4a5SThomas Graf 	}
3085c26bf4a5SThomas Graf 
30861da177e4SLinus Torvalds 	return skb;
30871da177e4SLinus Torvalds }
30881da177e4SLinus Torvalds 
3089475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev,
30901da177e4SLinus Torvalds 				   struct pktgen_dev *pkt_dev)
30911da177e4SLinus Torvalds {
30921da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
30931da177e4SLinus Torvalds 		return fill_packet_ipv6(odev, pkt_dev);
30941da177e4SLinus Torvalds 	else
30951da177e4SLinus Torvalds 		return fill_packet_ipv4(odev, pkt_dev);
30961da177e4SLinus Torvalds }
30971da177e4SLinus Torvalds 
30981da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
30991da177e4SLinus Torvalds {
31001da177e4SLinus Torvalds 	pkt_dev->seq_num = 1;
31011da177e4SLinus Torvalds 	pkt_dev->idle_acc = 0;
31021da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
31031da177e4SLinus Torvalds 	pkt_dev->tx_bytes = 0;
31041da177e4SLinus Torvalds 	pkt_dev->errors = 0;
31051da177e4SLinus Torvalds }
31061da177e4SLinus Torvalds 
31071da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */
31081da177e4SLinus Torvalds 
31091da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t)
31101da177e4SLinus Torvalds {
3111c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
31121da177e4SLinus Torvalds 	int started = 0;
31131da177e4SLinus Torvalds 
3114f9467eaeSJoe Perches 	func_enter();
31151da177e4SLinus Torvalds 
31168788370aSJesper Dangaard Brouer 	rcu_read_lock();
31178788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
31181da177e4SLinus Torvalds 
31191da177e4SLinus Torvalds 		/*
31201da177e4SLinus Torvalds 		 * setup odev and create initial packet.
31211da177e4SLinus Torvalds 		 */
31221da177e4SLinus Torvalds 		pktgen_setup_inject(pkt_dev);
31231da177e4SLinus Torvalds 
31241da177e4SLinus Torvalds 		if (pkt_dev->odev) {
31251da177e4SLinus Torvalds 			pktgen_clear_counters(pkt_dev);
31261da177e4SLinus Torvalds 			pkt_dev->skb = NULL;
3127398f382cSDaniel Borkmann 			pkt_dev->started_at = pkt_dev->next_tx = ktime_get();
3128fd29cf72SStephen Hemminger 
312916dab72fSJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
31301da177e4SLinus Torvalds 
31311da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Starting");
31328788370aSJesper Dangaard Brouer 			pkt_dev->running = 1;	/* Cranke yeself! */
31331da177e4SLinus Torvalds 			started++;
3134222f1806SLuiz Capitulino 		} else
31351da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Error starting");
31361da177e4SLinus Torvalds 	}
31378788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3138222f1806SLuiz Capitulino 	if (started)
3139222f1806SLuiz Capitulino 		t->control &= ~(T_STOP);
31401da177e4SLinus Torvalds }
31411da177e4SLinus Torvalds 
31424e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn)
31431da177e4SLinus Torvalds {
3144cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31451da177e4SLinus Torvalds 
3146f9467eaeSJoe Perches 	func_enter();
31471da177e4SLinus Torvalds 
31486146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3149cdcdbe0bSLuiz Capitulino 
31504e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
315195ed63f7SArthur Kepner 		t->control |= T_STOP;
3152cdcdbe0bSLuiz Capitulino 
31536146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
31541da177e4SLinus Torvalds }
31551da177e4SLinus Torvalds 
3156648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t)
31571da177e4SLinus Torvalds {
3158648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
31591da177e4SLinus Torvalds 
31608788370aSJesper Dangaard Brouer 	rcu_read_lock();
31618788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
31628788370aSJesper Dangaard Brouer 		if (pkt_dev->running) {
31638788370aSJesper Dangaard Brouer 			rcu_read_unlock();
3164648fda74SStephen Hemminger 			return 1;
31658788370aSJesper Dangaard Brouer 		}
31668788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3167648fda74SStephen Hemminger 	return 0;
31681da177e4SLinus Torvalds }
31691da177e4SLinus Torvalds 
31701da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t)
31711da177e4SLinus Torvalds {
31721da177e4SLinus Torvalds 	while (thread_is_running(t)) {
31731da177e4SLinus Torvalds 
31741da177e4SLinus Torvalds 		msleep_interruptible(100);
31751da177e4SLinus Torvalds 
31761da177e4SLinus Torvalds 		if (signal_pending(current))
31771da177e4SLinus Torvalds 			goto signal;
31781da177e4SLinus Torvalds 	}
31791da177e4SLinus Torvalds 	return 1;
31801da177e4SLinus Torvalds signal:
31811da177e4SLinus Torvalds 	return 0;
31821da177e4SLinus Torvalds }
31831da177e4SLinus Torvalds 
31844e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
31851da177e4SLinus Torvalds {
3186cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31871da177e4SLinus Torvalds 	int sig = 1;
31881da177e4SLinus Torvalds 
31896146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3190cdcdbe0bSLuiz Capitulino 
31914e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
31921da177e4SLinus Torvalds 		sig = pktgen_wait_thread_run(t);
3193222f1806SLuiz Capitulino 		if (sig == 0)
3194222f1806SLuiz Capitulino 			break;
31951da177e4SLinus Torvalds 	}
3196cdcdbe0bSLuiz Capitulino 
3197cdcdbe0bSLuiz Capitulino 	if (sig == 0)
31984e58a027SCong Wang 		list_for_each_entry(t, &pn->pktgen_threads, th_list)
31991da177e4SLinus Torvalds 			t->control |= (T_STOP);
3200cdcdbe0bSLuiz Capitulino 
32016146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32021da177e4SLinus Torvalds 	return sig;
32031da177e4SLinus Torvalds }
32041da177e4SLinus Torvalds 
32054e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn)
32061da177e4SLinus Torvalds {
3207cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
32081da177e4SLinus Torvalds 
3209f9467eaeSJoe Perches 	func_enter();
32101da177e4SLinus Torvalds 
32116146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
32121da177e4SLinus Torvalds 
32134e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
32141da177e4SLinus Torvalds 		t->control |= (T_RUN);
3215cdcdbe0bSLuiz Capitulino 
32166146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32171da177e4SLinus Torvalds 
321863adc6fbSStephen Hemminger 	/* Propagate thread->control  */
321963adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
32201da177e4SLinus Torvalds 
32214e58a027SCong Wang 	pktgen_wait_all_threads_run(pn);
32221da177e4SLinus Torvalds }
32231da177e4SLinus Torvalds 
32244e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn)
3225eb37b41cSJesse Brandeburg {
3226eb37b41cSJesse Brandeburg 	struct pktgen_thread *t;
3227eb37b41cSJesse Brandeburg 
3228f9467eaeSJoe Perches 	func_enter();
3229eb37b41cSJesse Brandeburg 
3230eb37b41cSJesse Brandeburg 	mutex_lock(&pktgen_thread_lock);
3231eb37b41cSJesse Brandeburg 
32324e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
3233eb37b41cSJesse Brandeburg 		t->control |= (T_REMDEVALL);
3234eb37b41cSJesse Brandeburg 
3235eb37b41cSJesse Brandeburg 	mutex_unlock(&pktgen_thread_lock);
3236eb37b41cSJesse Brandeburg 
323763adc6fbSStephen Hemminger 	/* Propagate thread->control  */
323863adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
3239eb37b41cSJesse Brandeburg 
32404e58a027SCong Wang 	pktgen_wait_all_threads_run(pn);
3241eb37b41cSJesse Brandeburg }
3242eb37b41cSJesse Brandeburg 
32431da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
32441da177e4SLinus Torvalds {
3245fd29cf72SStephen Hemminger 	__u64 bps, mbps, pps;
32461da177e4SLinus Torvalds 	char *p = pkt_dev->result;
3247fd29cf72SStephen Hemminger 	ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
3248fd29cf72SStephen Hemminger 				    pkt_dev->started_at);
3249fd29cf72SStephen Hemminger 	ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
32501da177e4SLinus Torvalds 
325103a14ab1SDaniel Turull 	p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
3252fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(elapsed),
3253fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
3254fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(idle),
32551da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->sofar,
32561da177e4SLinus Torvalds 		     pkt_dev->cur_pkt_size, nr_frags);
32571da177e4SLinus Torvalds 
3258fd29cf72SStephen Hemminger 	pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
3259fd29cf72SStephen Hemminger 			ktime_to_ns(elapsed));
32601da177e4SLinus Torvalds 
32611da177e4SLinus Torvalds 	bps = pps * 8 * pkt_dev->cur_pkt_size;
32621da177e4SLinus Torvalds 
32631da177e4SLinus Torvalds 	mbps = bps;
32641da177e4SLinus Torvalds 	do_div(mbps, 1000000);
32651da177e4SLinus Torvalds 	p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
32661da177e4SLinus Torvalds 		     (unsigned long long)pps,
32671da177e4SLinus Torvalds 		     (unsigned long long)mbps,
32681da177e4SLinus Torvalds 		     (unsigned long long)bps,
32691da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->errors);
32701da177e4SLinus Torvalds }
32711da177e4SLinus Torvalds 
32721da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */
32731da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
32741da177e4SLinus Torvalds {
3275222f1806SLuiz Capitulino 	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
32761da177e4SLinus Torvalds 
32771da177e4SLinus Torvalds 	if (!pkt_dev->running) {
3278294a0b7fSJoe Perches 		pr_warn("interface: %s is already stopped\n",
3279f9467eaeSJoe Perches 			pkt_dev->odevname);
32801da177e4SLinus Torvalds 		return -EINVAL;
32811da177e4SLinus Torvalds 	}
32821da177e4SLinus Torvalds 
32838788370aSJesper Dangaard Brouer 	pkt_dev->running = 0;
32843bda06a3SStephen Hemminger 	kfree_skb(pkt_dev->skb);
32853bda06a3SStephen Hemminger 	pkt_dev->skb = NULL;
3286398f382cSDaniel Borkmann 	pkt_dev->stopped_at = ktime_get();
32871da177e4SLinus Torvalds 
328895ed63f7SArthur Kepner 	show_results(pkt_dev, nr_frags);
32891da177e4SLinus Torvalds 
32901da177e4SLinus Torvalds 	return 0;
32911da177e4SLinus Torvalds }
32921da177e4SLinus Torvalds 
32931da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
32941da177e4SLinus Torvalds {
3295c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev, *best = NULL;
32961da177e4SLinus Torvalds 
32978788370aSJesper Dangaard Brouer 	rcu_read_lock();
32988788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3299c26a8016SLuiz Capitulino 		if (!pkt_dev->running)
3300222f1806SLuiz Capitulino 			continue;
3301222f1806SLuiz Capitulino 		if (best == NULL)
3302c26a8016SLuiz Capitulino 			best = pkt_dev;
3303398f382cSDaniel Borkmann 		else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0)
3304c26a8016SLuiz Capitulino 			best = pkt_dev;
33051da177e4SLinus Torvalds 	}
33068788370aSJesper Dangaard Brouer 	rcu_read_unlock();
33078788370aSJesper Dangaard Brouer 
33081da177e4SLinus Torvalds 	return best;
33091da177e4SLinus Torvalds }
33101da177e4SLinus Torvalds 
3311222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t)
3312222f1806SLuiz Capitulino {
3313c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
33141da177e4SLinus Torvalds 
3315f9467eaeSJoe Perches 	func_enter();
33161da177e4SLinus Torvalds 
33178788370aSJesper Dangaard Brouer 	rcu_read_lock();
33181da177e4SLinus Torvalds 
33198788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3320c26a8016SLuiz Capitulino 		pktgen_stop_device(pkt_dev);
332195ed63f7SArthur Kepner 	}
332295ed63f7SArthur Kepner 
33238788370aSJesper Dangaard Brouer 	rcu_read_unlock();
332495ed63f7SArthur Kepner }
332595ed63f7SArthur Kepner 
332695ed63f7SArthur Kepner /*
332795ed63f7SArthur Kepner  * one of our devices needs to be removed - find it
332895ed63f7SArthur Kepner  * and remove it
332995ed63f7SArthur Kepner  */
333095ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t)
333195ed63f7SArthur Kepner {
3332c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3333c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
333495ed63f7SArthur Kepner 
3335f9467eaeSJoe Perches 	func_enter();
333695ed63f7SArthur Kepner 
3337c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3338c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
333995ed63f7SArthur Kepner 
3340222f1806SLuiz Capitulino 		if (!cur->removal_mark)
3341222f1806SLuiz Capitulino 			continue;
334295ed63f7SArthur Kepner 
334395ed63f7SArthur Kepner 		kfree_skb(cur->skb);
334495ed63f7SArthur Kepner 		cur->skb = NULL;
334595ed63f7SArthur Kepner 
334695ed63f7SArthur Kepner 		pktgen_remove_device(t, cur);
334795ed63f7SArthur Kepner 
334895ed63f7SArthur Kepner 		break;
334995ed63f7SArthur Kepner 	}
33501da177e4SLinus Torvalds }
33511da177e4SLinus Torvalds 
33521da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t)
33531da177e4SLinus Torvalds {
3354c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3355c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
33561da177e4SLinus Torvalds 
3357f9467eaeSJoe Perches 	func_enter();
3358f9467eaeSJoe Perches 
33591da177e4SLinus Torvalds 	/* Remove all devices, free mem */
33601da177e4SLinus Torvalds 
3361c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3362c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
336395ed63f7SArthur Kepner 
336495ed63f7SArthur Kepner 		kfree_skb(cur->skb);
336595ed63f7SArthur Kepner 		cur->skb = NULL;
336695ed63f7SArthur Kepner 
33671da177e4SLinus Torvalds 		pktgen_remove_device(t, cur);
33681da177e4SLinus Torvalds 	}
33691da177e4SLinus Torvalds }
33701da177e4SLinus Torvalds 
33711da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t)
33721da177e4SLinus Torvalds {
33731da177e4SLinus Torvalds 	/* Remove from the thread list */
33744e58a027SCong Wang 	remove_proc_entry(t->tsk->comm, t->net->proc_dir);
33751da177e4SLinus Torvalds }
33761da177e4SLinus Torvalds 
3377ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev)
33783791decbSStephen Hemminger {
3379398f382cSDaniel Borkmann 	ktime_t idle_start = ktime_get();
33803791decbSStephen Hemminger 	schedule();
3381398f382cSDaniel Borkmann 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
33823791decbSStephen Hemminger }
33833791decbSStephen Hemminger 
3384ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
3385ef87979cSStephen Hemminger {
3386398f382cSDaniel Borkmann 	ktime_t idle_start = ktime_get();
3387ef87979cSStephen Hemminger 
338863354797SReshetova, Elena 	while (refcount_read(&(pkt_dev->skb->users)) != 1) {
3389ef87979cSStephen Hemminger 		if (signal_pending(current))
3390ef87979cSStephen Hemminger 			break;
3391ef87979cSStephen Hemminger 
3392ef87979cSStephen Hemminger 		if (need_resched())
3393ef87979cSStephen Hemminger 			pktgen_resched(pkt_dev);
3394ef87979cSStephen Hemminger 		else
3395ef87979cSStephen Hemminger 			cpu_relax();
3396ef87979cSStephen Hemminger 	}
3397398f382cSDaniel Borkmann 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
3398ef87979cSStephen Hemminger }
3399fd29cf72SStephen Hemminger 
3400475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev)
34011da177e4SLinus Torvalds {
34026aa7de05SMark Rutland 	unsigned int burst = READ_ONCE(pkt_dev->burst);
340300829823SStephen Hemminger 	struct net_device *odev = pkt_dev->odev;
3404fd2ea0a7SDavid S. Miller 	struct netdev_queue *txq;
340562f64aedSAlexei Starovoitov 	struct sk_buff *skb;
34061da177e4SLinus Torvalds 	int ret;
34071da177e4SLinus Torvalds 
3408ef87979cSStephen Hemminger 	/* If device is offline, then don't send */
3409ef87979cSStephen Hemminger 	if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) {
34101da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
34113791decbSStephen Hemminger 		return;
34121da177e4SLinus Torvalds 	}
34131da177e4SLinus Torvalds 
3414ef87979cSStephen Hemminger 	/* This is max DELAY, this has special meaning of
3415ef87979cSStephen Hemminger 	 * "never transmit"
3416ef87979cSStephen Hemminger 	 */
3417ef87979cSStephen Hemminger 	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
3418398f382cSDaniel Borkmann 		pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX);
3419ef87979cSStephen Hemminger 		return;
3420ef87979cSStephen Hemminger 	}
3421ef87979cSStephen Hemminger 
3422ef87979cSStephen Hemminger 	/* If no skb or clone count exhausted then get new one */
34237d7bb1cfSStephen Hemminger 	if (!pkt_dev->skb || (pkt_dev->last_ok &&
34247d7bb1cfSStephen Hemminger 			      ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
34251da177e4SLinus Torvalds 		/* build a new pkt */
34261da177e4SLinus Torvalds 		kfree_skb(pkt_dev->skb);
34271da177e4SLinus Torvalds 
34281da177e4SLinus Torvalds 		pkt_dev->skb = fill_packet(odev, pkt_dev);
34291da177e4SLinus Torvalds 		if (pkt_dev->skb == NULL) {
3430f9467eaeSJoe Perches 			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
34311da177e4SLinus Torvalds 			schedule();
34321da177e4SLinus Torvalds 			pkt_dev->clone_count--;	/* back out increment, OOM */
34333791decbSStephen Hemminger 			return;
34341da177e4SLinus Torvalds 		}
3435baac8564SEric Dumazet 		pkt_dev->last_pkt_size = pkt_dev->skb->len;
34361da177e4SLinus Torvalds 		pkt_dev->clone_count = 0;	/* reset counter */
34371da177e4SLinus Torvalds 	}
34381da177e4SLinus Torvalds 
3439ef87979cSStephen Hemminger 	if (pkt_dev->delay && pkt_dev->last_ok)
3440ef87979cSStephen Hemminger 		spin(pkt_dev, pkt_dev->next_tx);
3441ef87979cSStephen Hemminger 
344262f64aedSAlexei Starovoitov 	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) {
344362f64aedSAlexei Starovoitov 		skb = pkt_dev->skb;
344462f64aedSAlexei Starovoitov 		skb->protocol = eth_type_trans(skb, skb->dev);
344563354797SReshetova, Elena 		refcount_add(burst, &skb->users);
344662f64aedSAlexei Starovoitov 		local_bh_disable();
344762f64aedSAlexei Starovoitov 		do {
344862f64aedSAlexei Starovoitov 			ret = netif_receive_skb(skb);
344962f64aedSAlexei Starovoitov 			if (ret == NET_RX_DROP)
345062f64aedSAlexei Starovoitov 				pkt_dev->errors++;
345162f64aedSAlexei Starovoitov 			pkt_dev->sofar++;
345262f64aedSAlexei Starovoitov 			pkt_dev->seq_num++;
345363354797SReshetova, Elena 			if (refcount_read(&skb->users) != burst) {
345462f64aedSAlexei Starovoitov 				/* skb was queued by rps/rfs or taps,
345562f64aedSAlexei Starovoitov 				 * so cannot reuse this skb
345662f64aedSAlexei Starovoitov 				 */
345763354797SReshetova, Elena 				WARN_ON(refcount_sub_and_test(burst - 1, &skb->users));
345862f64aedSAlexei Starovoitov 				/* get out of the loop and wait
345962f64aedSAlexei Starovoitov 				 * until skb is consumed
346062f64aedSAlexei Starovoitov 				 */
346162f64aedSAlexei Starovoitov 				break;
346262f64aedSAlexei Starovoitov 			}
346362f64aedSAlexei Starovoitov 			/* skb was 'freed' by stack, so clean few
346462f64aedSAlexei Starovoitov 			 * bits and reuse it
346562f64aedSAlexei Starovoitov 			 */
3466a5135bcfSWillem de Bruijn 			skb_reset_tc(skb);
346762f64aedSAlexei Starovoitov 		} while (--burst > 0);
346862f64aedSAlexei Starovoitov 		goto out; /* Skips xmit_mode M_START_XMIT */
34690967f244SJohn Fastabend 	} else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) {
34700967f244SJohn Fastabend 		local_bh_disable();
347163354797SReshetova, Elena 		refcount_inc(&pkt_dev->skb->users);
34720967f244SJohn Fastabend 
34730967f244SJohn Fastabend 		ret = dev_queue_xmit(pkt_dev->skb);
34740967f244SJohn Fastabend 		switch (ret) {
34750967f244SJohn Fastabend 		case NET_XMIT_SUCCESS:
34760967f244SJohn Fastabend 			pkt_dev->sofar++;
34770967f244SJohn Fastabend 			pkt_dev->seq_num++;
34780967f244SJohn Fastabend 			pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
34790967f244SJohn Fastabend 			break;
34800967f244SJohn Fastabend 		case NET_XMIT_DROP:
34810967f244SJohn Fastabend 		case NET_XMIT_CN:
34820967f244SJohn Fastabend 		/* These are all valid return codes for a qdisc but
34830967f244SJohn Fastabend 		 * indicate packets are being dropped or will likely
34840967f244SJohn Fastabend 		 * be dropped soon.
34850967f244SJohn Fastabend 		 */
34860967f244SJohn Fastabend 		case NETDEV_TX_BUSY:
34870967f244SJohn Fastabend 		/* qdisc may call dev_hard_start_xmit directly in cases
34880967f244SJohn Fastabend 		 * where no queues exist e.g. loopback device, virtual
34890967f244SJohn Fastabend 		 * devices, etc. In this case we need to handle
34900967f244SJohn Fastabend 		 * NETDEV_TX_ codes.
34910967f244SJohn Fastabend 		 */
34920967f244SJohn Fastabend 		default:
34930967f244SJohn Fastabend 			pkt_dev->errors++;
34940967f244SJohn Fastabend 			net_info_ratelimited("%s xmit error: %d\n",
34950967f244SJohn Fastabend 					     pkt_dev->odevname, ret);
34960967f244SJohn Fastabend 			break;
34970967f244SJohn Fastabend 		}
34980967f244SJohn Fastabend 		goto out;
349962f64aedSAlexei Starovoitov 	}
350062f64aedSAlexei Starovoitov 
350110c51b56SDaniel Borkmann 	txq = skb_get_tx_queue(odev, pkt_dev->skb);
3502fd2ea0a7SDavid S. Miller 
35030f2eea4bSDaniel Borkmann 	local_bh_disable();
35040f2eea4bSDaniel Borkmann 
35050f2eea4bSDaniel Borkmann 	HARD_TX_LOCK(odev, txq, smp_processor_id());
35065b8db2f5SStephen Hemminger 
35076f25cd47SDaniel Borkmann 	if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) {
3508ef87979cSStephen Hemminger 		ret = NETDEV_TX_BUSY;
35090835acfeSEric Dumazet 		pkt_dev->last_ok = 0;
35100835acfeSEric Dumazet 		goto unlock;
35110835acfeSEric Dumazet 	}
351263354797SReshetova, Elena 	refcount_add(burst, &pkt_dev->skb->users);
351338b2cf29SAlexei Starovoitov 
351438b2cf29SAlexei Starovoitov xmit_more:
351538b2cf29SAlexei Starovoitov 	ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0);
3516ef87979cSStephen Hemminger 
35175b8db2f5SStephen Hemminger 	switch (ret) {
35185b8db2f5SStephen Hemminger 	case NETDEV_TX_OK:
35191da177e4SLinus Torvalds 		pkt_dev->last_ok = 1;
35201da177e4SLinus Torvalds 		pkt_dev->sofar++;
35211da177e4SLinus Torvalds 		pkt_dev->seq_num++;
3522baac8564SEric Dumazet 		pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
352338b2cf29SAlexei Starovoitov 		if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq))
352438b2cf29SAlexei Starovoitov 			goto xmit_more;
35255b8db2f5SStephen Hemminger 		break;
3526f466dba1SJohn Fastabend 	case NET_XMIT_DROP:
3527f466dba1SJohn Fastabend 	case NET_XMIT_CN:
3528f466dba1SJohn Fastabend 		/* skb has been consumed */
3529f466dba1SJohn Fastabend 		pkt_dev->errors++;
3530f466dba1SJohn Fastabend 		break;
35315b8db2f5SStephen Hemminger 	default: /* Drivers are not supposed to return other values! */
3532e87cc472SJoe Perches 		net_info_ratelimited("%s xmit error: %d\n",
3533e87cc472SJoe Perches 				     pkt_dev->odevname, ret);
35341da177e4SLinus Torvalds 		pkt_dev->errors++;
35355b8db2f5SStephen Hemminger 		/* fallthru */
35365b8db2f5SStephen Hemminger 	case NETDEV_TX_BUSY:
35375b8db2f5SStephen Hemminger 		/* Retry it next time */
353863354797SReshetova, Elena 		refcount_dec(&(pkt_dev->skb->users));
35391da177e4SLinus Torvalds 		pkt_dev->last_ok = 0;
35401da177e4SLinus Torvalds 	}
354138b2cf29SAlexei Starovoitov 	if (unlikely(burst))
354263354797SReshetova, Elena 		WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users));
35430835acfeSEric Dumazet unlock:
35440f2eea4bSDaniel Borkmann 	HARD_TX_UNLOCK(odev, txq);
35450f2eea4bSDaniel Borkmann 
354662f64aedSAlexei Starovoitov out:
35470f2eea4bSDaniel Borkmann 	local_bh_enable();
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 
357683144186SRafael J. Wysocki 	set_freezable();
357783144186SRafael J. Wysocki 
3578ee74baa7SDavid S. Miller 	while (!kthread_should_stop()) {
3579ee74baa7SDavid S. Miller 		pkt_dev = next_to_run(t);
3580ee74baa7SDavid S. Miller 
3581ef87979cSStephen Hemminger 		if (unlikely(!pkt_dev && t->control == 0)) {
35824e58a027SCong Wang 			if (t->net->pktgen_exiting)
3583551eaff1SEric Dumazet 				break;
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 
3591ef87979cSStephen Hemminger 		if (likely(pkt_dev)) {
35921da177e4SLinus Torvalds 			pktgen_xmit(pkt_dev);
35931da177e4SLinus Torvalds 
3594ef87979cSStephen Hemminger 			if (need_resched())
3595ef87979cSStephen Hemminger 				pktgen_resched(pkt_dev);
3596ef87979cSStephen Hemminger 			else
3597ef87979cSStephen Hemminger 				cpu_relax();
3598ef87979cSStephen Hemminger 		}
3599ef87979cSStephen Hemminger 
36001da177e4SLinus Torvalds 		if (t->control & T_STOP) {
36011da177e4SLinus Torvalds 			pktgen_stop(t);
36021da177e4SLinus Torvalds 			t->control &= ~(T_STOP);
36031da177e4SLinus Torvalds 		}
36041da177e4SLinus Torvalds 
36051da177e4SLinus Torvalds 		if (t->control & T_RUN) {
36061da177e4SLinus Torvalds 			pktgen_run(t);
36071da177e4SLinus Torvalds 			t->control &= ~(T_RUN);
36081da177e4SLinus Torvalds 		}
36091da177e4SLinus Torvalds 
361095ed63f7SArthur Kepner 		if (t->control & T_REMDEVALL) {
36111da177e4SLinus Torvalds 			pktgen_rem_all_ifs(t);
361295ed63f7SArthur Kepner 			t->control &= ~(T_REMDEVALL);
361395ed63f7SArthur Kepner 		}
361495ed63f7SArthur Kepner 
361595ed63f7SArthur Kepner 		if (t->control & T_REMDEV) {
361695ed63f7SArthur Kepner 			pktgen_rem_one_if(t);
36171da177e4SLinus Torvalds 			t->control &= ~(T_REMDEV);
36181da177e4SLinus Torvalds 		}
36191da177e4SLinus Torvalds 
362009fe3ef4SAndrew Morton 		try_to_freeze();
36211da177e4SLinus Torvalds 	}
36221da177e4SLinus Torvalds 
3623f9467eaeSJoe Perches 	pr_debug("%s stopping all device\n", t->tsk->comm);
36241da177e4SLinus Torvalds 	pktgen_stop(t);
36251da177e4SLinus Torvalds 
3626f9467eaeSJoe Perches 	pr_debug("%s removing all device\n", t->tsk->comm);
36271da177e4SLinus Torvalds 	pktgen_rem_all_ifs(t);
36281da177e4SLinus Torvalds 
3629f9467eaeSJoe Perches 	pr_debug("%s removing thread\n", t->tsk->comm);
36301da177e4SLinus Torvalds 	pktgen_rem_thread(t);
3631cdcdbe0bSLuiz Capitulino 
3632ee74baa7SDavid S. Miller 	return 0;
36331da177e4SLinus Torvalds }
36341da177e4SLinus Torvalds 
3635222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
36363e984840SEric Dumazet 					  const char *ifname, bool exact)
36371da177e4SLinus Torvalds {
3638c26a8016SLuiz Capitulino 	struct pktgen_dev *p, *pkt_dev = NULL;
36393e984840SEric Dumazet 	size_t len = strlen(ifname);
36401da177e4SLinus Torvalds 
36418788370aSJesper Dangaard Brouer 	rcu_read_lock();
36428788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(p, &t->if_list, list)
36433e984840SEric Dumazet 		if (strncmp(p->odevname, ifname, len) == 0) {
36443e984840SEric Dumazet 			if (p->odevname[len]) {
36453e984840SEric Dumazet 				if (exact || p->odevname[len] != '@')
36463e984840SEric Dumazet 					continue;
36473e984840SEric Dumazet 			}
3648c26a8016SLuiz Capitulino 			pkt_dev = p;
36491da177e4SLinus Torvalds 			break;
36501da177e4SLinus Torvalds 		}
36511da177e4SLinus Torvalds 
36528788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3653f9467eaeSJoe Perches 	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
36541da177e4SLinus Torvalds 	return pkt_dev;
36551da177e4SLinus Torvalds }
36561da177e4SLinus Torvalds 
36571da177e4SLinus Torvalds /*
36581da177e4SLinus Torvalds  * Adds a dev at front of if_list.
36591da177e4SLinus Torvalds  */
36601da177e4SLinus Torvalds 
3661222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t,
3662222f1806SLuiz Capitulino 			     struct pktgen_dev *pkt_dev)
36631da177e4SLinus Torvalds {
36641da177e4SLinus Torvalds 	int rv = 0;
36651da177e4SLinus Torvalds 
36668788370aSJesper Dangaard Brouer 	/* This function cannot be called concurrently, as its called
36678788370aSJesper Dangaard Brouer 	 * under pktgen_thread_lock mutex, but it can run from
36688788370aSJesper Dangaard Brouer 	 * userspace on another CPU than the kthread.  The if_lock()
36698788370aSJesper Dangaard Brouer 	 * is used here to sync with concurrent instances of
36708788370aSJesper Dangaard Brouer 	 * _rem_dev_from_if_list() invoked via kthread, which is also
36718788370aSJesper Dangaard Brouer 	 * updating the if_list */
36721da177e4SLinus Torvalds 	if_lock(t);
36731da177e4SLinus Torvalds 
36741da177e4SLinus Torvalds 	if (pkt_dev->pg_thread) {
3675f9467eaeSJoe Perches 		pr_err("ERROR: already assigned to a thread\n");
36761da177e4SLinus Torvalds 		rv = -EBUSY;
36771da177e4SLinus Torvalds 		goto out;
36781da177e4SLinus Torvalds 	}
3679c26a8016SLuiz Capitulino 
36801da177e4SLinus Torvalds 	pkt_dev->running = 0;
36818788370aSJesper Dangaard Brouer 	pkt_dev->pg_thread = t;
36828788370aSJesper Dangaard Brouer 	list_add_rcu(&pkt_dev->list, &t->if_list);
36831da177e4SLinus Torvalds 
36841da177e4SLinus Torvalds out:
36851da177e4SLinus Torvalds 	if_unlock(t);
36861da177e4SLinus Torvalds 	return rv;
36871da177e4SLinus Torvalds }
36881da177e4SLinus Torvalds 
36891da177e4SLinus Torvalds /* Called under thread lock */
36901da177e4SLinus Torvalds 
36911da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
36921da177e4SLinus Torvalds {
36931da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev;
369439df232fSStephen Hemminger 	int err;
36953291b9dbSEric Dumazet 	int node = cpu_to_node(t->cpu);
36961da177e4SLinus Torvalds 
36971da177e4SLinus Torvalds 	/* We don't allow a device to be on several threads */
36981da177e4SLinus Torvalds 
36994e58a027SCong Wang 	pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND);
3700d50a6b56SStephen Hemminger 	if (pkt_dev) {
3701f9467eaeSJoe Perches 		pr_err("ERROR: interface already used\n");
3702d50a6b56SStephen Hemminger 		return -EBUSY;
3703d50a6b56SStephen Hemminger 	}
37041da177e4SLinus Torvalds 
37053291b9dbSEric Dumazet 	pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node);
37061da177e4SLinus Torvalds 	if (!pkt_dev)
37071da177e4SLinus Torvalds 		return -ENOMEM;
37081da177e4SLinus Torvalds 
3709593f63b0SEric Dumazet 	strcpy(pkt_dev->odevname, ifname);
371068d5ac2eSWANG Cong 	pkt_dev->flows = vzalloc_node(MAX_CFLOWS * sizeof(struct flow_state),
37113291b9dbSEric Dumazet 				      node);
37121da177e4SLinus Torvalds 	if (pkt_dev->flows == NULL) {
37131da177e4SLinus Torvalds 		kfree(pkt_dev);
37141da177e4SLinus Torvalds 		return -ENOMEM;
37151da177e4SLinus Torvalds 	}
37161da177e4SLinus Torvalds 
371795ed63f7SArthur Kepner 	pkt_dev->removal_mark = 0;
37181da177e4SLinus Torvalds 	pkt_dev->nfrags = 0;
3719fd29cf72SStephen Hemminger 	pkt_dev->delay = pg_delay_d;
37201da177e4SLinus Torvalds 	pkt_dev->count = pg_count_d;
37211da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
37221da177e4SLinus Torvalds 	pkt_dev->udp_src_min = 9;	/* sink port */
37231da177e4SLinus Torvalds 	pkt_dev->udp_src_max = 9;
37241da177e4SLinus Torvalds 	pkt_dev->udp_dst_min = 9;
37251da177e4SLinus Torvalds 	pkt_dev->udp_dst_max = 9;
372634954ddcSFrancesco Fondelli 	pkt_dev->vlan_p = 0;
372734954ddcSFrancesco Fondelli 	pkt_dev->vlan_cfi = 0;
372834954ddcSFrancesco Fondelli 	pkt_dev->vlan_id = 0xffff;
372934954ddcSFrancesco Fondelli 	pkt_dev->svlan_p = 0;
373034954ddcSFrancesco Fondelli 	pkt_dev->svlan_cfi = 0;
373134954ddcSFrancesco Fondelli 	pkt_dev->svlan_id = 0xffff;
373238b2cf29SAlexei Starovoitov 	pkt_dev->burst = 1;
3733e99b99b4SRobert Olsson 	pkt_dev->node = -1;
373434954ddcSFrancesco Fondelli 
37354e58a027SCong Wang 	err = pktgen_setup_dev(t->net, pkt_dev, ifname);
373639df232fSStephen Hemminger 	if (err)
373739df232fSStephen Hemminger 		goto out1;
3738d8873315SNeil Horman 	if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
3739d8873315SNeil Horman 		pkt_dev->clone_skb = pg_clone_skb_d;
37401da177e4SLinus Torvalds 
37414e58a027SCong Wang 	pkt_dev->entry = proc_create_data(ifname, 0600, t->net->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;
3752cf93d47eSFan Du 
3753cf93d47eSFan Du 	/* xfrm tunnel mode needs additional dst to extract outter
3754cf93d47eSFan Du 	 * ip header protocol/ttl/id field, here creat a phony one.
3755cf93d47eSFan Du 	 * instead of looking for a valid rt, which definitely hurting
3756cf93d47eSFan Du 	 * performance under such circumstance.
3757cf93d47eSFan Du 	 */
3758cf93d47eSFan Du 	pkt_dev->dstops.family = AF_INET;
3759b6ca8bd5SDavid Miller 	pkt_dev->xdst.u.dst.dev = pkt_dev->odev;
3760b6ca8bd5SDavid Miller 	dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false);
3761b6ca8bd5SDavid Miller 	pkt_dev->xdst.child = &pkt_dev->xdst.u.dst;
3762b6ca8bd5SDavid Miller 	pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops;
3763a553e4a6SJamal Hadi Salim #endif
376439df232fSStephen Hemminger 
376539df232fSStephen Hemminger 	return add_dev_to_thread(t, pkt_dev);
376639df232fSStephen Hemminger out2:
376739df232fSStephen Hemminger 	dev_put(pkt_dev->odev);
376839df232fSStephen Hemminger out1:
3769a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3770a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3771a553e4a6SJamal Hadi Salim #endif
37721da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
37731da177e4SLinus Torvalds 	kfree(pkt_dev);
377439df232fSStephen Hemminger 	return err;
37751da177e4SLinus Torvalds }
37761da177e4SLinus Torvalds 
37774e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
37781da177e4SLinus Torvalds {
3779cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3780d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3781ee74baa7SDavid S. Miller 	struct task_struct *p;
37821da177e4SLinus Torvalds 
37833291b9dbSEric Dumazet 	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
37843291b9dbSEric Dumazet 			 cpu_to_node(cpu));
37851da177e4SLinus Torvalds 	if (!t) {
3786f9467eaeSJoe Perches 		pr_err("ERROR: out of memory, can't create new thread\n");
37871da177e4SLinus Torvalds 		return -ENOMEM;
37881da177e4SLinus Torvalds 	}
37891da177e4SLinus Torvalds 
37909a0b1e8bSEric Dumazet 	mutex_init(&t->if_lock);
37911da177e4SLinus Torvalds 	t->cpu = cpu;
37921da177e4SLinus Torvalds 
3793ee74baa7SDavid S. Miller 	INIT_LIST_HEAD(&t->if_list);
3794ee74baa7SDavid S. Miller 
37954e58a027SCong Wang 	list_add_tail(&t->th_list, &pn->pktgen_threads);
3796d3ede327SDenis V. Lunev 	init_completion(&t->start_done);
3797ee74baa7SDavid S. Miller 
379894dcf29aSEric Dumazet 	p = kthread_create_on_node(pktgen_thread_worker,
379994dcf29aSEric Dumazet 				   t,
380094dcf29aSEric Dumazet 				   cpu_to_node(cpu),
380194dcf29aSEric Dumazet 				   "kpktgend_%d", cpu);
3802ee74baa7SDavid S. Miller 	if (IS_ERR(p)) {
3803f9467eaeSJoe Perches 		pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
3804ee74baa7SDavid S. Miller 		list_del(&t->th_list);
3805ee74baa7SDavid S. Miller 		kfree(t);
3806ee74baa7SDavid S. Miller 		return PTR_ERR(p);
3807ee74baa7SDavid S. Miller 	}
3808ee74baa7SDavid S. Miller 	kthread_bind(p, cpu);
3809ee74baa7SDavid S. Miller 	t->tsk = p;
3810ee74baa7SDavid S. Miller 
38114e58a027SCong Wang 	pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir,
38125efdccbcSDenis V. Lunev 			      &pktgen_thread_fops, t);
3813d50a6b56SStephen Hemminger 	if (!pe) {
3814f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3815ee74baa7SDavid S. Miller 		       PG_PROC_DIR, t->tsk->comm);
3816ee74baa7SDavid S. Miller 		kthread_stop(p);
3817ee74baa7SDavid S. Miller 		list_del(&t->th_list);
38181da177e4SLinus Torvalds 		kfree(t);
38191da177e4SLinus Torvalds 		return -EINVAL;
38201da177e4SLinus Torvalds 	}
3821d50a6b56SStephen Hemminger 
38224e58a027SCong Wang 	t->net = pn;
38231fbe4b46SOleg Nesterov 	get_task_struct(p);
3824ee74baa7SDavid S. Miller 	wake_up_process(p);
3825d3ede327SDenis V. Lunev 	wait_for_completion(&t->start_done);
38261da177e4SLinus Torvalds 
38271da177e4SLinus Torvalds 	return 0;
38281da177e4SLinus Torvalds }
38291da177e4SLinus Torvalds 
38301da177e4SLinus Torvalds /*
38311da177e4SLinus Torvalds  * Removes a device from the thread if_list.
38321da177e4SLinus Torvalds  */
3833222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t,
3834222f1806SLuiz Capitulino 				  struct pktgen_dev *pkt_dev)
38351da177e4SLinus Torvalds {
3836c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3837c26a8016SLuiz Capitulino 	struct pktgen_dev *p;
38381da177e4SLinus Torvalds 
38398788370aSJesper Dangaard Brouer 	if_lock(t);
3840c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3841c26a8016SLuiz Capitulino 		p = list_entry(q, struct pktgen_dev, list);
3842c26a8016SLuiz Capitulino 		if (p == pkt_dev)
38438788370aSJesper Dangaard Brouer 			list_del_rcu(&p->list);
38441da177e4SLinus Torvalds 	}
38458788370aSJesper Dangaard Brouer 	if_unlock(t);
38461da177e4SLinus Torvalds }
38471da177e4SLinus Torvalds 
3848222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t,
3849222f1806SLuiz Capitulino 				struct pktgen_dev *pkt_dev)
38501da177e4SLinus Torvalds {
3851f9467eaeSJoe Perches 	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
38521da177e4SLinus Torvalds 
38531da177e4SLinus Torvalds 	if (pkt_dev->running) {
3854294a0b7fSJoe Perches 		pr_warn("WARNING: trying to remove a running interface, stopping it now\n");
38551da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
38561da177e4SLinus Torvalds 	}
38571da177e4SLinus Torvalds 
38581da177e4SLinus Torvalds 	/* Dis-associate from the interface */
38591da177e4SLinus Torvalds 
38601da177e4SLinus Torvalds 	if (pkt_dev->odev) {
38611da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
38621da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
38631da177e4SLinus Torvalds 	}
38641da177e4SLinus Torvalds 
38658788370aSJesper Dangaard Brouer 	/* Remove proc before if_list entry, because add_device uses
38668788370aSJesper Dangaard Brouer 	 * list to determine if interface already exist, avoid race
38678788370aSJesper Dangaard Brouer 	 * with proc_create_data() */
3868a8ca16eaSDavid Howells 	proc_remove(pkt_dev->entry);
38691da177e4SLinus Torvalds 
38708788370aSJesper Dangaard Brouer 	/* And update the thread if_list */
38718788370aSJesper Dangaard Brouer 	_rem_dev_from_if_list(t, pkt_dev);
38728788370aSJesper Dangaard Brouer 
3873a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3874a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3875a553e4a6SJamal Hadi Salim #endif
38761da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
387726ad7879SEric Dumazet 	if (pkt_dev->page)
387826ad7879SEric Dumazet 		put_page(pkt_dev->page);
38798788370aSJesper Dangaard Brouer 	kfree_rcu(pkt_dev, rcu);
38801da177e4SLinus Torvalds 	return 0;
38811da177e4SLinus Torvalds }
38821da177e4SLinus Torvalds 
38834e58a027SCong Wang static int __net_init pg_net_init(struct net *net)
38841da177e4SLinus Torvalds {
38854e58a027SCong Wang 	struct pktgen_net *pn = net_generic(net, pg_net_id);
3886d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
38874e58a027SCong Wang 	int cpu, ret = 0;
3888d50a6b56SStephen Hemminger 
38894e58a027SCong Wang 	pn->net = net;
38904e58a027SCong Wang 	INIT_LIST_HEAD(&pn->pktgen_threads);
38914e58a027SCong Wang 	pn->pktgen_exiting = false;
38924e58a027SCong Wang 	pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net);
38934e58a027SCong Wang 	if (!pn->proc_dir) {
38944e58a027SCong Wang 		pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR);
3895d50a6b56SStephen Hemminger 		return -ENODEV;
38961da177e4SLinus Torvalds 	}
38974e58a027SCong Wang 	pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops);
38984e58a027SCong Wang 	if (pe == NULL) {
38994e58a027SCong Wang 		pr_err("cannot create %s procfs entry\n", PGCTRL);
39004e58a027SCong Wang 		ret = -EINVAL;
39014e58a027SCong Wang 		goto remove;
39024e58a027SCong Wang 	}
39031da177e4SLinus Torvalds 
3904670c02c2SJohn Hawkes 	for_each_online_cpu(cpu) {
39058024bb24SLuiz Capitulino 		int err;
39061da177e4SLinus Torvalds 
39074e58a027SCong Wang 		err = pktgen_create_thread(cpu, pn);
39088024bb24SLuiz Capitulino 		if (err)
39094e58a027SCong Wang 			pr_warn("Cannot create thread for cpu %d (%d)\n",
3910f9467eaeSJoe Perches 				   cpu, err);
39111da177e4SLinus Torvalds 	}
39128024bb24SLuiz Capitulino 
39134e58a027SCong Wang 	if (list_empty(&pn->pktgen_threads)) {
39144e58a027SCong Wang 		pr_err("Initialization failed for all threads\n");
3915ce14f894SWANG Cong 		ret = -ENODEV;
39164e58a027SCong Wang 		goto remove_entry;
39178024bb24SLuiz Capitulino 	}
39188024bb24SLuiz Capitulino 
39191da177e4SLinus Torvalds 	return 0;
3920ce14f894SWANG Cong 
39214e58a027SCong Wang remove_entry:
39224e58a027SCong Wang 	remove_proc_entry(PGCTRL, pn->proc_dir);
39234e58a027SCong Wang remove:
3924ece31ffdSGao feng 	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
3925ce14f894SWANG Cong 	return ret;
39261da177e4SLinus Torvalds }
39271da177e4SLinus Torvalds 
39284e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net)
39291da177e4SLinus Torvalds {
39304e58a027SCong Wang 	struct pktgen_net *pn = net_generic(net, pg_net_id);
3931cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3932cdcdbe0bSLuiz Capitulino 	struct list_head *q, *n;
3933d4b11335SEric Dumazet 	LIST_HEAD(list);
39341da177e4SLinus Torvalds 
39351da177e4SLinus Torvalds 	/* Stop all interfaces & threads */
39364e58a027SCong Wang 	pn->pktgen_exiting = true;
39371da177e4SLinus Torvalds 
3938c57b5468SEric Dumazet 	mutex_lock(&pktgen_thread_lock);
39394e58a027SCong Wang 	list_splice_init(&pn->pktgen_threads, &list);
3940c57b5468SEric Dumazet 	mutex_unlock(&pktgen_thread_lock);
3941c57b5468SEric Dumazet 
3942c57b5468SEric Dumazet 	list_for_each_safe(q, n, &list) {
3943cdcdbe0bSLuiz Capitulino 		t = list_entry(q, struct pktgen_thread, th_list);
3944c57b5468SEric Dumazet 		list_del(&t->th_list);
3945ee74baa7SDavid S. Miller 		kthread_stop(t->tsk);
39461fbe4b46SOleg Nesterov 		put_task_struct(t->tsk);
3947ee74baa7SDavid S. Miller 		kfree(t);
39481da177e4SLinus Torvalds 	}
39491da177e4SLinus Torvalds 
39504e58a027SCong Wang 	remove_proc_entry(PGCTRL, pn->proc_dir);
3951ece31ffdSGao feng 	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
39524e58a027SCong Wang }
39531da177e4SLinus Torvalds 
39544e58a027SCong Wang static struct pernet_operations pg_net_ops = {
39554e58a027SCong Wang 	.init = pg_net_init,
39564e58a027SCong Wang 	.exit = pg_net_exit,
39574e58a027SCong Wang 	.id   = &pg_net_id,
39584e58a027SCong Wang 	.size = sizeof(struct pktgen_net),
39594e58a027SCong Wang };
39604e58a027SCong Wang 
39614e58a027SCong Wang static int __init pg_init(void)
39624e58a027SCong Wang {
39634e58a027SCong Wang 	int ret = 0;
39644e58a027SCong Wang 
39654e58a027SCong Wang 	pr_info("%s", version);
39664e58a027SCong Wang 	ret = register_pernet_subsys(&pg_net_ops);
39674e58a027SCong Wang 	if (ret)
39684e58a027SCong Wang 		return ret;
39694e58a027SCong Wang 	ret = register_netdevice_notifier(&pktgen_notifier_block);
39704e58a027SCong Wang 	if (ret)
39714e58a027SCong Wang 		unregister_pernet_subsys(&pg_net_ops);
39724e58a027SCong Wang 
39734e58a027SCong Wang 	return ret;
39744e58a027SCong Wang }
39754e58a027SCong Wang 
39764e58a027SCong Wang static void __exit pg_cleanup(void)
39774e58a027SCong Wang {
39784e58a027SCong Wang 	unregister_netdevice_notifier(&pktgen_notifier_block);
39794e58a027SCong Wang 	unregister_pernet_subsys(&pg_net_ops);
39808788370aSJesper Dangaard Brouer 	/* Don't need rcu_barrier() due to use of kfree_rcu() */
39811da177e4SLinus Torvalds }
39821da177e4SLinus Torvalds 
39831da177e4SLinus Torvalds module_init(pg_init);
39841da177e4SLinus Torvalds module_exit(pg_cleanup);
39851da177e4SLinus Torvalds 
3986c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
39871da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool");
39881da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3989c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION);
39901da177e4SLinus Torvalds module_param(pg_count_d, int, 0);
3991c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
39921da177e4SLinus Torvalds module_param(pg_delay_d, int, 0);
3993c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
39941da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0);
3995c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
39961da177e4SLinus Torvalds module_param(debug, int, 0);
3997c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");
3998