xref: /openbmc/linux/net/core/pktgen.c (revision cda9de0b8daf2ebfc07d385ef0039fd7860ddf25)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Authors:
41da177e4SLinus Torvalds  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
51da177e4SLinus Torvalds  *                             Uppsala University and
61da177e4SLinus Torvalds  *                             Swedish University of Agricultural Sciences
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Alexey Kuznetsov  <kuznet@ms2.inr.ac.ru>
91da177e4SLinus Torvalds  * Ben Greear <greearb@candelatech.com>
1096de0e25SJan Engelhardt  * Jens Låås <jens.laas@data.slu.se>
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * A tool for loading the network with preconfigurated packets.
131da177e4SLinus Torvalds  * The tool is implemented as a linux module.  Parameters are output
141da177e4SLinus Torvalds  * device, delay (to hard_xmit), number of packets, and whether
151da177e4SLinus Torvalds  * to use multiple SKBs or just the same one.
161da177e4SLinus Torvalds  * pktgen uses the installed interface's output routine.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * Additional hacking by:
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  * Jens.Laas@data.slu.se
211da177e4SLinus Torvalds  * Improved by ANK. 010120.
221da177e4SLinus Torvalds  * Improved by ANK even more. 010212.
231da177e4SLinus Torvalds  * MAC address typo fixed. 010417 --ro
241da177e4SLinus Torvalds  * Integrated.  020301 --DaveM
251da177e4SLinus Torvalds  * Added multiskb option 020301 --DaveM
261da177e4SLinus Torvalds  * Scaling of results. 020417--sigurdur@linpro.no
271da177e4SLinus Torvalds  * Significant re-work of the module:
281da177e4SLinus Torvalds  *   *  Convert to threaded model to more efficiently be able to transmit
291da177e4SLinus Torvalds  *       and receive on multiple interfaces at once.
301da177e4SLinus Torvalds  *   *  Converted many counters to __u64 to allow longer runs.
311da177e4SLinus Torvalds  *   *  Allow configuration of ranges, like min/max IP address, MACs,
321da177e4SLinus Torvalds  *       and UDP-ports, for both source and destination, and can
331da177e4SLinus Torvalds  *       set to use a random distribution or sequentially walk the range.
341da177e4SLinus Torvalds  *   *  Can now change most values after starting.
351da177e4SLinus Torvalds  *   *  Place 12-byte packet in UDP payload with magic number,
361da177e4SLinus Torvalds  *       sequence number, and timestamp.
371da177e4SLinus Torvalds  *   *  Add receiver code that detects dropped pkts, re-ordered pkts, and
381da177e4SLinus Torvalds  *       latencies (with micro-second) precision.
391da177e4SLinus Torvalds  *   *  Add IOCTL interface to easily get counters & configuration.
401da177e4SLinus Torvalds  *   --Ben Greear <greearb@candelatech.com>
411da177e4SLinus Torvalds  *
421da177e4SLinus Torvalds  * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
431da177e4SLinus Torvalds  * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
441da177e4SLinus Torvalds  * as a "fastpath" with a configurable number of clones after alloc's.
451da177e4SLinus Torvalds  * clone_skb=0 means all packets are allocated this also means ranges time
461da177e4SLinus Torvalds  * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
471da177e4SLinus Torvalds  * clones.
481da177e4SLinus Torvalds  *
491da177e4SLinus Torvalds  * Also moved to /proc/net/pktgen/
501da177e4SLinus Torvalds  * --ro
511da177e4SLinus Torvalds  *
521da177e4SLinus Torvalds  * Sept 10:  Fixed threading/locking.  Lots of bone-headed and more clever
531da177e4SLinus Torvalds  *    mistakes.  Also merged in DaveM's patch in the -pre6 patch.
541da177e4SLinus Torvalds  * --Ben Greear <greearb@candelatech.com>
551da177e4SLinus Torvalds  *
561da177e4SLinus Torvalds  * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
571da177e4SLinus Torvalds  *
581da177e4SLinus Torvalds  * 021124 Finished major redesign and rewrite for new functionality.
59c1e4535fSMauro Carvalho Chehab  * See Documentation/networking/pktgen.rst for how to use this.
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  * The new operation:
621da177e4SLinus Torvalds  * For each CPU one thread/process is created at start. This process checks
631da177e4SLinus Torvalds  * for running devices in the if_list and sends packets until count is 0 it
641da177e4SLinus Torvalds  * also the thread checks the thread->control which is used for inter-process
651da177e4SLinus Torvalds  * communication. controlling process "posts" operations to the threads this
668788370aSJesper Dangaard Brouer  * way.
678788370aSJesper Dangaard Brouer  * The if_list is RCU protected, and the if_lock remains to protect updating
688788370aSJesper Dangaard Brouer  * of if_list, from "add_device" as it invoked from userspace (via proc write).
691da177e4SLinus Torvalds  *
701da177e4SLinus Torvalds  * By design there should only be *one* "controlling" process. In practice
711da177e4SLinus Torvalds  * multiple write accesses gives unpredictable result. Understood by "write"
721da177e4SLinus Torvalds  * to /proc gives result code thats should be read be the "writer".
73b4099fabSStephen Hemminger  * For practical use this should be no problem.
741da177e4SLinus Torvalds  *
751da177e4SLinus Torvalds  * Note when adding devices to a specific CPU there good idea to also assign
761da177e4SLinus Torvalds  * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU.
771da177e4SLinus Torvalds  * --ro
781da177e4SLinus Torvalds  *
791da177e4SLinus Torvalds  * Fix refcount off by one if first packet fails, potential null deref,
801da177e4SLinus Torvalds  * memleak 030710- KJP
811da177e4SLinus Torvalds  *
821da177e4SLinus Torvalds  * First "ranges" functionality for ipv6 030726 --ro
831da177e4SLinus Torvalds  *
841da177e4SLinus Torvalds  * Included flow support. 030802 ANK.
851da177e4SLinus Torvalds  *
861da177e4SLinus Torvalds  * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
871da177e4SLinus Torvalds  *
881da177e4SLinus Torvalds  * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
891da177e4SLinus Torvalds  * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
901da177e4SLinus Torvalds  *
911da177e4SLinus Torvalds  * New xmit() return, do_div and misc clean up by Stephen Hemminger
921da177e4SLinus Torvalds  * <shemminger@osdl.org> 040923
931da177e4SLinus Torvalds  *
94ca9f1fd2SStephen Hemminger  * Randy Dunlap fixed u64 printk compiler warning
951da177e4SLinus Torvalds  *
961da177e4SLinus Torvalds  * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
971da177e4SLinus Torvalds  * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
981da177e4SLinus Torvalds  *
991da177e4SLinus Torvalds  * Corrections from Nikolai Malykh (nmalykh@bilim.com)
1001da177e4SLinus Torvalds  * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
1011da177e4SLinus Torvalds  *
1021da177e4SLinus Torvalds  * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
1031da177e4SLinus Torvalds  * 050103
104ca6549afSSteven Whitehouse  *
105ca6549afSSteven Whitehouse  * MPLS support by Steven Whitehouse <steve@chygwyn.com>
106ca6549afSSteven Whitehouse  *
10734954ddcSFrancesco Fondelli  * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
10834954ddcSFrancesco Fondelli  *
109ce5d0b47SAdit Ranadive  * Fixed src_mac command to set source mac of packet to value specified in
110ce5d0b47SAdit Ranadive  * command by Adit Ranadive <adit.262@gmail.com>
1111da177e4SLinus Torvalds  */
112f9467eaeSJoe Perches 
113f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
114f9467eaeSJoe Perches 
1151da177e4SLinus Torvalds #include <linux/sys.h>
1161da177e4SLinus Torvalds #include <linux/types.h>
1171da177e4SLinus Torvalds #include <linux/module.h>
1181da177e4SLinus Torvalds #include <linux/moduleparam.h>
1191da177e4SLinus Torvalds #include <linux/kernel.h>
120222fa076SLuiz Capitulino #include <linux/mutex.h>
1211da177e4SLinus Torvalds #include <linux/sched.h>
1221da177e4SLinus Torvalds #include <linux/slab.h>
1231da177e4SLinus Torvalds #include <linux/vmalloc.h>
1241da177e4SLinus Torvalds #include <linux/unistd.h>
1251da177e4SLinus Torvalds #include <linux/string.h>
1261da177e4SLinus Torvalds #include <linux/ptrace.h>
1271da177e4SLinus Torvalds #include <linux/errno.h>
1281da177e4SLinus Torvalds #include <linux/ioport.h>
1291da177e4SLinus Torvalds #include <linux/interrupt.h>
1304fc268d2SRandy Dunlap #include <linux/capability.h>
1312bc481cfSStephen Hemminger #include <linux/hrtimer.h>
13209fe3ef4SAndrew Morton #include <linux/freezer.h>
1331da177e4SLinus Torvalds #include <linux/delay.h>
1341da177e4SLinus Torvalds #include <linux/timer.h>
135cdcdbe0bSLuiz Capitulino #include <linux/list.h>
1361da177e4SLinus Torvalds #include <linux/init.h>
1371da177e4SLinus Torvalds #include <linux/skbuff.h>
1381da177e4SLinus Torvalds #include <linux/netdevice.h>
1391da177e4SLinus Torvalds #include <linux/inet.h>
1401da177e4SLinus Torvalds #include <linux/inetdevice.h>
1411da177e4SLinus Torvalds #include <linux/rtnetlink.h>
1421da177e4SLinus Torvalds #include <linux/if_arp.h>
14334954ddcSFrancesco Fondelli #include <linux/if_vlan.h>
1441da177e4SLinus Torvalds #include <linux/in.h>
1451da177e4SLinus Torvalds #include <linux/ip.h>
1461da177e4SLinus Torvalds #include <linux/ipv6.h>
1471da177e4SLinus Torvalds #include <linux/udp.h>
1481da177e4SLinus Torvalds #include <linux/proc_fs.h>
149d50a6b56SStephen Hemminger #include <linux/seq_file.h>
1501da177e4SLinus Torvalds #include <linux/wait.h>
151f404e9a6SKris Katterjohn #include <linux/etherdevice.h>
152ee74baa7SDavid S. Miller #include <linux/kthread.h>
153268bb0ceSLinus Torvalds #include <linux/prefetch.h>
15498fa15f3SAnshuman Khandual #include <linux/mmzone.h>
155457c4cbcSEric W. Biederman #include <net/net_namespace.h>
1561da177e4SLinus Torvalds #include <net/checksum.h>
1571da177e4SLinus Torvalds #include <net/ipv6.h>
158c26bf4a5SThomas Graf #include <net/udp.h>
15973d94e94SStephen Rothwell #include <net/ip6_checksum.h>
1601da177e4SLinus Torvalds #include <net/addrconf.h>
161a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
162a553e4a6SJamal Hadi Salim #include <net/xfrm.h>
163a553e4a6SJamal Hadi Salim #endif
1644e58a027SCong Wang #include <net/netns/generic.h>
1651da177e4SLinus Torvalds #include <asm/byteorder.h>
1661da177e4SLinus Torvalds #include <linux/rcupdate.h>
1671977f032SJiri Slaby #include <linux/bitops.h>
16863adc6fbSStephen Hemminger #include <linux/io.h>
16963adc6fbSStephen Hemminger #include <linux/timex.h>
17063adc6fbSStephen Hemminger #include <linux/uaccess.h>
1711da177e4SLinus Torvalds #include <asm/dma.h>
1721da177e4SLinus Torvalds #include <asm/div64.h>		/* do_div */
1731da177e4SLinus Torvalds 
17440207264SJesper Dangaard Brouer #define VERSION	"2.75"
1751da177e4SLinus Torvalds #define IP_NAME_SZ 32
176ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
177d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100)
1781da177e4SLinus Torvalds 
179f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__);
180f9467eaeSJoe Perches 
1816f107c74SDmitry Safonov #define PKT_FLAGS							\
1826f107c74SDmitry Safonov 	pf(IPV6)		/* Interface in IPV6 Mode */		\
1836f107c74SDmitry Safonov 	pf(IPSRC_RND)		/* IP-Src Random  */			\
1846f107c74SDmitry Safonov 	pf(IPDST_RND)		/* IP-Dst Random  */			\
1856f107c74SDmitry Safonov 	pf(TXSIZE_RND)		/* Transmit size is random */		\
1866f107c74SDmitry Safonov 	pf(UDPSRC_RND)		/* UDP-Src Random */			\
1876f107c74SDmitry Safonov 	pf(UDPDST_RND)		/* UDP-Dst Random */			\
1886f107c74SDmitry Safonov 	pf(UDPCSUM)		/* Include UDP checksum */		\
1896f107c74SDmitry Safonov 	pf(NO_TIMESTAMP)	/* Don't timestamp packets (default TS) */ \
1906f107c74SDmitry Safonov 	pf(MPLS_RND)		/* Random MPLS labels */		\
1916f107c74SDmitry Safonov 	pf(QUEUE_MAP_RND)	/* queue map Random */			\
1926f107c74SDmitry Safonov 	pf(QUEUE_MAP_CPU)	/* queue map mirrors smp_processor_id() */ \
1936f107c74SDmitry Safonov 	pf(FLOW_SEQ)		/* Sequential flows */			\
1946f107c74SDmitry Safonov 	pf(IPSEC)		/* ipsec on for flows */		\
1956f107c74SDmitry Safonov 	pf(MACSRC_RND)		/* MAC-Src Random */			\
1966f107c74SDmitry Safonov 	pf(MACDST_RND)		/* MAC-Dst Random */			\
1976f107c74SDmitry Safonov 	pf(VID_RND)		/* Random VLAN ID */			\
1986f107c74SDmitry Safonov 	pf(SVID_RND)		/* Random SVLAN ID */			\
1996f107c74SDmitry Safonov 	pf(NODE)		/* Node memory alloc*/			\
2006f107c74SDmitry Safonov 
2016f107c74SDmitry Safonov #define pf(flag)		flag##_SHIFT,
2026f107c74SDmitry Safonov enum pkt_flags {
2036f107c74SDmitry Safonov 	PKT_FLAGS
2046f107c74SDmitry Safonov };
2056f107c74SDmitry Safonov #undef pf
2066f107c74SDmitry Safonov 
2071da177e4SLinus Torvalds /* Device flag bits */
2086f107c74SDmitry Safonov #define pf(flag)		static const __u32 F_##flag = (1<<flag##_SHIFT);
2096f107c74SDmitry Safonov PKT_FLAGS
2106f107c74SDmitry Safonov #undef pf
2111da177e4SLinus Torvalds 
21299c6d3d2SDmitry Safonov #define pf(flag)		__stringify(flag),
21399c6d3d2SDmitry Safonov static char *pkt_flag_names[] = {
21499c6d3d2SDmitry Safonov 	PKT_FLAGS
21599c6d3d2SDmitry Safonov };
21699c6d3d2SDmitry Safonov #undef pf
21799c6d3d2SDmitry Safonov 
21899c6d3d2SDmitry Safonov #define NR_PKT_FLAGS		ARRAY_SIZE(pkt_flag_names)
21999c6d3d2SDmitry Safonov 
2201da177e4SLinus Torvalds /* Thread control flag bits */
2216b80d6a6SStephen Hemminger #define T_STOP        (1<<0)	/* Stop run */
2226b80d6a6SStephen Hemminger #define T_RUN         (1<<1)	/* Start run */
2236b80d6a6SStephen Hemminger #define T_REMDEVALL   (1<<2)	/* Remove all devs */
2246b80d6a6SStephen Hemminger #define T_REMDEV      (1<<3)	/* Remove one dev */
2251da177e4SLinus Torvalds 
22662f64aedSAlexei Starovoitov /* Xmit modes */
22762f64aedSAlexei Starovoitov #define M_START_XMIT		0	/* Default normal TX */
22862f64aedSAlexei Starovoitov #define M_NETIF_RECEIVE 	1	/* Inject packets into stack */
2290967f244SJohn Fastabend #define M_QUEUE_XMIT		2	/* Inject packet into qdisc */
23062f64aedSAlexei Starovoitov 
2318788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */
2329a0b1e8bSEric Dumazet #define   if_lock(t)           mutex_lock(&(t->if_lock));
2339a0b1e8bSEric Dumazet #define   if_unlock(t)           mutex_unlock(&(t->if_lock));
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */
2361da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955
237d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen"
238d50a6b56SStephen Hemminger #define PGCTRL	    "pgctrl"
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds #define MAX_CFLOWS  65536
2411da177e4SLinus Torvalds 
24234954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
24334954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
24434954ddcSFrancesco Fondelli 
245222f1806SLuiz Capitulino struct flow_state {
246252e3346SAl Viro 	__be32 cur_daddr;
2471da177e4SLinus Torvalds 	int count;
248a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
249a553e4a6SJamal Hadi Salim 	struct xfrm_state *x;
250a553e4a6SJamal Hadi Salim #endif
251007a531bSJamal Hadi Salim 	__u32 flags;
2521da177e4SLinus Torvalds };
2531da177e4SLinus Torvalds 
254007a531bSJamal Hadi Salim /* flow flag bits */
255007a531bSJamal Hadi Salim #define F_INIT   (1<<0)		/* flow has been initialized */
256007a531bSJamal Hadi Salim 
2571da177e4SLinus Torvalds struct pktgen_dev {
2581da177e4SLinus Torvalds 	/*
2591da177e4SLinus Torvalds 	 * Try to keep frequent/infrequent used vars. separated.
2601da177e4SLinus Torvalds 	 */
26139df232fSStephen Hemminger 	struct proc_dir_entry *entry;	/* proc file */
2621da177e4SLinus Torvalds 	struct pktgen_thread *pg_thread;/* the owner */
26363adc6fbSStephen Hemminger 	struct list_head list;		/* chaining in the thread's run-queue */
2648788370aSJesper Dangaard Brouer 	struct rcu_head	 rcu;		/* freed by RCU */
2651da177e4SLinus Torvalds 
26663adc6fbSStephen Hemminger 	int running;		/* if false, the test will stop */
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	/* If min != max, then we will either do a linear iteration, or
2691da177e4SLinus Torvalds 	 * we will do a random selection from within the range.
2701da177e4SLinus Torvalds 	 */
2711da177e4SLinus Torvalds 	__u32 flags;
27262f64aedSAlexei Starovoitov 	int xmit_mode;
27368bf9f0bSAmerigo Wang 	int min_pkt_size;
27468bf9f0bSAmerigo Wang 	int max_pkt_size;
27516dab72fSJamal Hadi Salim 	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
2761da177e4SLinus Torvalds 	int nfrags;
27762f64aedSAlexei Starovoitov 	int removal_mark;	/* non-zero => the device is marked for
27862f64aedSAlexei Starovoitov 				 * removal by worker thread */
27962f64aedSAlexei Starovoitov 
28026ad7879SEric Dumazet 	struct page *page;
281fd29cf72SStephen Hemminger 	u64 delay;		/* nano-seconds */
282fd29cf72SStephen Hemminger 
2831da177e4SLinus Torvalds 	__u64 count;		/* Default No packets to send */
2841da177e4SLinus Torvalds 	__u64 sofar;		/* How many pkts we've sent so far */
2851da177e4SLinus Torvalds 	__u64 tx_bytes;		/* How many bytes we've transmitted */
286f466dba1SJohn Fastabend 	__u64 errors;		/* Errors when trying to transmit, */
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	/* runtime counters relating to clone_skb */
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	__u32 clone_count;
2911da177e4SLinus Torvalds 	int last_ok;		/* Was last skb sent?
29263adc6fbSStephen Hemminger 				 * Or a failed transmit of some sort?
29363adc6fbSStephen Hemminger 				 * This will keep sequence numbers in order
2941da177e4SLinus Torvalds 				 */
295fd29cf72SStephen Hemminger 	ktime_t next_tx;
296fd29cf72SStephen Hemminger 	ktime_t started_at;
297fd29cf72SStephen Hemminger 	ktime_t stopped_at;
298fd29cf72SStephen Hemminger 	u64	idle_acc;	/* nano-seconds */
299fd29cf72SStephen Hemminger 
3001da177e4SLinus Torvalds 	__u32 seq_num;
3011da177e4SLinus Torvalds 
30263adc6fbSStephen Hemminger 	int clone_skb;		/*
30363adc6fbSStephen Hemminger 				 * Use multiple SKBs during packet gen.
30463adc6fbSStephen Hemminger 				 * If this number is greater than 1, then
30563adc6fbSStephen Hemminger 				 * that many copies of the same packet will be
30663adc6fbSStephen Hemminger 				 * sent before a new packet is allocated.
30763adc6fbSStephen Hemminger 				 * If you want to send 1024 identical packets
30863adc6fbSStephen Hemminger 				 * before creating a new packet,
30963adc6fbSStephen Hemminger 				 * set clone_skb to 1024.
3101da177e4SLinus Torvalds 				 */
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	char dst_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3131da177e4SLinus Torvalds 	char dst_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3141da177e4SLinus Torvalds 	char src_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3151da177e4SLinus Torvalds 	char src_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 	struct in6_addr in6_saddr;
3181da177e4SLinus Torvalds 	struct in6_addr in6_daddr;
3191da177e4SLinus Torvalds 	struct in6_addr cur_in6_daddr;
3201da177e4SLinus Torvalds 	struct in6_addr cur_in6_saddr;
3211da177e4SLinus Torvalds 	/* For ranges */
3221da177e4SLinus Torvalds 	struct in6_addr min_in6_daddr;
3231da177e4SLinus Torvalds 	struct in6_addr max_in6_daddr;
3241da177e4SLinus Torvalds 	struct in6_addr min_in6_saddr;
3251da177e4SLinus Torvalds 	struct in6_addr max_in6_saddr;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	/* If we're doing ranges, random or incremental, then this
3281da177e4SLinus Torvalds 	 * defines the min/max for those ranges.
3291da177e4SLinus Torvalds 	 */
330252e3346SAl Viro 	__be32 saddr_min;	/* inclusive, source IP address */
331252e3346SAl Viro 	__be32 saddr_max;	/* exclusive, source IP address */
332252e3346SAl Viro 	__be32 daddr_min;	/* inclusive, dest IP address */
333252e3346SAl Viro 	__be32 daddr_max;	/* exclusive, dest IP address */
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	__u16 udp_src_min;	/* inclusive, source UDP port */
3361da177e4SLinus Torvalds 	__u16 udp_src_max;	/* exclusive, source UDP port */
3371da177e4SLinus Torvalds 	__u16 udp_dst_min;	/* inclusive, dest UDP port */
3381da177e4SLinus Torvalds 	__u16 udp_dst_max;	/* exclusive, dest UDP port */
3391da177e4SLinus Torvalds 
3401ca7768cSFrancesco Fondelli 	/* DSCP + ECN */
34163adc6fbSStephen Hemminger 	__u8 tos;            /* six MSB of (former) IPv4 TOS
34263adc6fbSStephen Hemminger 				are for dscp codepoint */
34363adc6fbSStephen Hemminger 	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6
34463adc6fbSStephen Hemminger 				(see RFC 3260, sec. 4) */
3451ca7768cSFrancesco Fondelli 
346ca6549afSSteven Whitehouse 	/* MPLS */
34795c96174SEric Dumazet 	unsigned int nr_labels;	/* Depth of stack, 0 = no MPLS */
348ca6549afSSteven Whitehouse 	__be32 labels[MAX_MPLS_LABELS];
349ca6549afSSteven Whitehouse 
35034954ddcSFrancesco Fondelli 	/* VLAN/SVLAN (802.1Q/Q-in-Q) */
35134954ddcSFrancesco Fondelli 	__u8  vlan_p;
35234954ddcSFrancesco Fondelli 	__u8  vlan_cfi;
35334954ddcSFrancesco Fondelli 	__u16 vlan_id;  /* 0xffff means no vlan tag */
35434954ddcSFrancesco Fondelli 
35534954ddcSFrancesco Fondelli 	__u8  svlan_p;
35634954ddcSFrancesco Fondelli 	__u8  svlan_cfi;
35734954ddcSFrancesco Fondelli 	__u16 svlan_id; /* 0xffff means no svlan tag */
35834954ddcSFrancesco Fondelli 
3591da177e4SLinus Torvalds 	__u32 src_mac_count;	/* How many MACs to iterate through */
3601da177e4SLinus Torvalds 	__u32 dst_mac_count;	/* How many MACs to iterate through */
3611da177e4SLinus Torvalds 
362f404e9a6SKris Katterjohn 	unsigned char dst_mac[ETH_ALEN];
363f404e9a6SKris Katterjohn 	unsigned char src_mac[ETH_ALEN];
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	__u32 cur_dst_mac_offset;
3661da177e4SLinus Torvalds 	__u32 cur_src_mac_offset;
367252e3346SAl Viro 	__be32 cur_saddr;
368252e3346SAl Viro 	__be32 cur_daddr;
36966ed1e5eSEric Dumazet 	__u16 ip_id;
3701da177e4SLinus Torvalds 	__u16 cur_udp_dst;
3711da177e4SLinus Torvalds 	__u16 cur_udp_src;
37245b270f8SRobert Olsson 	__u16 cur_queue_map;
3731da177e4SLinus Torvalds 	__u32 cur_pkt_size;
374baac8564SEric Dumazet 	__u32 last_pkt_size;
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	__u8 hh[14];
3771da177e4SLinus Torvalds 	/* = {
3781da177e4SLinus Torvalds 	   0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	   We fill in SRC address later
3811da177e4SLinus Torvalds 	   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3821da177e4SLinus Torvalds 	   0x08, 0x00
3831da177e4SLinus Torvalds 	   };
3841da177e4SLinus Torvalds 	 */
3851da177e4SLinus Torvalds 	__u16 pad;		/* pad out the hh struct to an even 16 bytes */
3861da177e4SLinus Torvalds 
38763adc6fbSStephen Hemminger 	struct sk_buff *skb;	/* skb we are to transmit next, used for when we
3881da177e4SLinus Torvalds 				 * are transmitting the same one multiple times
3891da177e4SLinus Torvalds 				 */
39063adc6fbSStephen Hemminger 	struct net_device *odev; /* The out-going device.
39163adc6fbSStephen Hemminger 				  * Note that the device should have it's
39263adc6fbSStephen Hemminger 				  * pg_info pointer pointing back to this
39363adc6fbSStephen Hemminger 				  * device.
39463adc6fbSStephen Hemminger 				  * Set when the user specifies the out-going
39563adc6fbSStephen Hemminger 				  * device name (not when the inject is
3961da177e4SLinus Torvalds 				  * started as it used to do.)
3971da177e4SLinus Torvalds 				  */
398593f63b0SEric Dumazet 	char odevname[32];
3991da177e4SLinus Torvalds 	struct flow_state *flows;
40095c96174SEric Dumazet 	unsigned int cflows;	/* Concurrent flows (config) */
40195c96174SEric Dumazet 	unsigned int lflow;		/* Flow length  (config) */
40295c96174SEric Dumazet 	unsigned int nflows;	/* accumulated flows (stats) */
40395c96174SEric Dumazet 	unsigned int curfl;		/* current sequenced flow (state)*/
40445b270f8SRobert Olsson 
40545b270f8SRobert Olsson 	u16 queue_map_min;
40645b270f8SRobert Olsson 	u16 queue_map_max;
4079e50e3acSJohn Fastabend 	__u32 skb_priority;	/* skb priority field */
40838b2cf29SAlexei Starovoitov 	unsigned int burst;	/* number of duplicated packets to burst */
409e99b99b4SRobert Olsson 	int node;               /* Memory node */
41045b270f8SRobert Olsson 
411a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
412a553e4a6SJamal Hadi Salim 	__u8	ipsmode;		/* IPSEC mode (config) */
413a553e4a6SJamal Hadi Salim 	__u8	ipsproto;		/* IPSEC type (config) */
414de4aee7dSFan Du 	__u32	spi;
415b6ca8bd5SDavid Miller 	struct xfrm_dst xdst;
416cf93d47eSFan Du 	struct dst_ops dstops;
417a553e4a6SJamal Hadi Salim #endif
41839df232fSStephen Hemminger 	char result[512];
4191da177e4SLinus Torvalds };
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds struct pktgen_hdr {
422252e3346SAl Viro 	__be32 pgh_magic;
423252e3346SAl Viro 	__be32 seq_num;
424252e3346SAl Viro 	__be32 tv_sec;
425252e3346SAl Viro 	__be32 tv_usec;
4261da177e4SLinus Torvalds };
4271da177e4SLinus Torvalds 
4284e58a027SCong Wang 
429c7d03a00SAlexey Dobriyan static unsigned int pg_net_id __read_mostly;
4304e58a027SCong Wang 
4314e58a027SCong Wang struct pktgen_net {
4324e58a027SCong Wang 	struct net		*net;
4334e58a027SCong Wang 	struct proc_dir_entry	*proc_dir;
4344e58a027SCong Wang 	struct list_head	pktgen_threads;
4354e58a027SCong Wang 	bool			pktgen_exiting;
4364e58a027SCong Wang };
437551eaff1SEric Dumazet 
4381da177e4SLinus Torvalds struct pktgen_thread {
4399a0b1e8bSEric Dumazet 	struct mutex if_lock;		/* for list of devices */
440c26a8016SLuiz Capitulino 	struct list_head if_list;	/* All device here */
441cdcdbe0bSLuiz Capitulino 	struct list_head th_list;
442ee74baa7SDavid S. Miller 	struct task_struct *tsk;
4431da177e4SLinus Torvalds 	char result[512];
4441da177e4SLinus Torvalds 
44563adc6fbSStephen Hemminger 	/* Field for thread to receive "posted" events terminate,
44663adc6fbSStephen Hemminger 	   stop ifs etc. */
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	u32 control;
4491da177e4SLinus Torvalds 	int cpu;
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	wait_queue_head_t queue;
452d3ede327SDenis V. Lunev 	struct completion start_done;
4534e58a027SCong Wang 	struct pktgen_net *net;
4541da177e4SLinus Torvalds };
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds #define REMOVE 1
4571da177e4SLinus Torvalds #define FIND   0
4581da177e4SLinus Torvalds 
459c3d2f52dSStephen Hemminger static const char version[] =
460f9467eaeSJoe Perches 	"Packet Generator for packet performance testing. "
461f9467eaeSJoe Perches 	"Version: " VERSION "\n";
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
4641da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
465222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
4663e984840SEric Dumazet 					  const char *ifname, bool exact);
4671da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
4684e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn);
4694e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn);
470*cda9de0bSYejune Deng static void pktgen_stop_all_threads(struct pktgen_net *pn);
4713bda06a3SStephen Hemminger 
4721da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t);
4731da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
47439df232fSStephen Hemminger 
4751da177e4SLinus Torvalds /* Module parameters, defaults. */
47665c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000;
47765c5b786SStephen Hemminger static int pg_delay_d __read_mostly;
47865c5b786SStephen Hemminger static int pg_clone_skb_d  __read_mostly;
47965c5b786SStephen Hemminger static int debug  __read_mostly;
4801da177e4SLinus Torvalds 
481222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock);
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = {
4841da177e4SLinus Torvalds 	.notifier_call = pktgen_device_event,
4851da177e4SLinus Torvalds };
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds /*
4881da177e4SLinus Torvalds  * /proc handling functions
4891da177e4SLinus Torvalds  *
4901da177e4SLinus Torvalds  */
4911da177e4SLinus Torvalds 
492d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v)
493d50a6b56SStephen Hemminger {
494c3d2f52dSStephen Hemminger 	seq_puts(seq, version);
495d50a6b56SStephen Hemminger 	return 0;
496d50a6b56SStephen Hemminger }
4971da177e4SLinus Torvalds 
498d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf,
4991da177e4SLinus Torvalds 			    size_t count, loff_t *ppos)
5001da177e4SLinus Torvalds {
501d50a6b56SStephen Hemminger 	char data[128];
5024e58a027SCong Wang 	struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
5031da177e4SLinus Torvalds 
50409455747SMathias Krause 	if (!capable(CAP_NET_ADMIN))
50509455747SMathias Krause 		return -EPERM;
5061da177e4SLinus Torvalds 
50720b0c718SMathias Krause 	if (count == 0)
50820b0c718SMathias Krause 		return -EINVAL;
50920b0c718SMathias Krause 
510d50a6b56SStephen Hemminger 	if (count > sizeof(data))
511d50a6b56SStephen Hemminger 		count = sizeof(data);
5121da177e4SLinus Torvalds 
51309455747SMathias Krause 	if (copy_from_user(data, buf, count))
51409455747SMathias Krause 		return -EFAULT;
51509455747SMathias Krause 
51620b0c718SMathias Krause 	data[count - 1] = 0;	/* Strip trailing '\n' and terminate string */
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	if (!strcmp(data, "stop"))
519*cda9de0bSYejune Deng 		pktgen_stop_all_threads(pn);
5201da177e4SLinus Torvalds 	else if (!strcmp(data, "start"))
5214e58a027SCong Wang 		pktgen_run_all_threads(pn);
522eb37b41cSJesse Brandeburg 	else if (!strcmp(data, "reset"))
5234e58a027SCong Wang 		pktgen_reset_all_threads(pn);
5241da177e4SLinus Torvalds 	else
52540207264SJesper Dangaard Brouer 		return -EINVAL;
5261da177e4SLinus Torvalds 
52709455747SMathias Krause 	return count;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds 
530d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file)
5311da177e4SLinus Torvalds {
532d9dda78bSAl Viro 	return single_open(file, pgctrl_show, PDE_DATA(inode));
533d50a6b56SStephen Hemminger }
534d50a6b56SStephen Hemminger 
53597a32539SAlexey Dobriyan static const struct proc_ops pktgen_proc_ops = {
53697a32539SAlexey Dobriyan 	.proc_open	= pgctrl_open,
53797a32539SAlexey Dobriyan 	.proc_read	= seq_read,
53897a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
53997a32539SAlexey Dobriyan 	.proc_write	= pgctrl_write,
54097a32539SAlexey Dobriyan 	.proc_release	= single_release,
541d50a6b56SStephen Hemminger };
542d50a6b56SStephen Hemminger 
543d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v)
544d50a6b56SStephen Hemminger {
545648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev = seq->private;
546fd29cf72SStephen Hemminger 	ktime_t stopped;
54799c6d3d2SDmitry Safonov 	unsigned int i;
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) {
60997dc48e2SThomas Graf 		seq_puts(seq, "     mpls: ");
610ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
611ca6549afSSteven Whitehouse 			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
612ca6549afSSteven Whitehouse 				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
613ca6549afSSteven Whitehouse 	}
614ca6549afSSteven Whitehouse 
61563adc6fbSStephen Hemminger 	if (pkt_dev->vlan_id != 0xffff)
61634954ddcSFrancesco Fondelli 		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
61763adc6fbSStephen Hemminger 			   pkt_dev->vlan_id, pkt_dev->vlan_p,
61863adc6fbSStephen Hemminger 			   pkt_dev->vlan_cfi);
61934954ddcSFrancesco Fondelli 
62063adc6fbSStephen Hemminger 	if (pkt_dev->svlan_id != 0xffff)
62134954ddcSFrancesco Fondelli 		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
62263adc6fbSStephen Hemminger 			   pkt_dev->svlan_id, pkt_dev->svlan_p,
62363adc6fbSStephen Hemminger 			   pkt_dev->svlan_cfi);
62434954ddcSFrancesco Fondelli 
62563adc6fbSStephen Hemminger 	if (pkt_dev->tos)
6261ca7768cSFrancesco Fondelli 		seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);
6271ca7768cSFrancesco Fondelli 
62863adc6fbSStephen Hemminger 	if (pkt_dev->traffic_class)
6291ca7768cSFrancesco Fondelli 		seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
6301ca7768cSFrancesco Fondelli 
63138b2cf29SAlexei Starovoitov 	if (pkt_dev->burst > 1)
63238b2cf29SAlexei Starovoitov 		seq_printf(seq, "     burst: %d\n", pkt_dev->burst);
63338b2cf29SAlexei Starovoitov 
634e99b99b4SRobert Olsson 	if (pkt_dev->node >= 0)
635e99b99b4SRobert Olsson 		seq_printf(seq, "     node: %d\n", pkt_dev->node);
636e99b99b4SRobert Olsson 
63762f64aedSAlexei Starovoitov 	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
63862f64aedSAlexei Starovoitov 		seq_puts(seq, "     xmit_mode: netif_receive\n");
6390967f244SJohn Fastabend 	else if (pkt_dev->xmit_mode == M_QUEUE_XMIT)
6400967f244SJohn Fastabend 		seq_puts(seq, "     xmit_mode: xmit_queue\n");
64162f64aedSAlexei Starovoitov 
64297dc48e2SThomas Graf 	seq_puts(seq, "     Flags: ");
643ca6549afSSteven Whitehouse 
64499c6d3d2SDmitry Safonov 	for (i = 0; i < NR_PKT_FLAGS; i++) {
64599c6d3d2SDmitry Safonov 		if (i == F_FLOW_SEQ)
64699c6d3d2SDmitry Safonov 			if (!pkt_dev->cflows)
64799c6d3d2SDmitry Safonov 				continue;
6481da177e4SLinus Torvalds 
64999c6d3d2SDmitry Safonov 		if (pkt_dev->flags & (1 << i))
65099c6d3d2SDmitry Safonov 			seq_printf(seq, "%s  ", pkt_flag_names[i]);
65199c6d3d2SDmitry Safonov 		else if (i == F_FLOW_SEQ)
65297dc48e2SThomas Graf 			seq_puts(seq, "FLOW_RND  ");
653007a531bSJamal Hadi Salim 
654a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
65599c6d3d2SDmitry Safonov 		if (i == F_IPSEC && pkt_dev->spi)
6568101328bSFan Du 			seq_printf(seq, "spi:%u", pkt_dev->spi);
657a553e4a6SJamal Hadi Salim #endif
65899c6d3d2SDmitry Safonov 	}
659e99b99b4SRobert Olsson 
660d50a6b56SStephen Hemminger 	seq_puts(seq, "\n");
6611da177e4SLinus Torvalds 
662fd29cf72SStephen Hemminger 	/* not really stopped, more like last-running-at */
663398f382cSDaniel Borkmann 	stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at;
664fd29cf72SStephen Hemminger 	idle = pkt_dev->idle_acc;
665fd29cf72SStephen Hemminger 	do_div(idle, NSEC_PER_USEC);
6661da177e4SLinus Torvalds 
667222f1806SLuiz Capitulino 	seq_printf(seq,
668fd29cf72SStephen Hemminger 		   "Current:\n     pkts-sofar: %llu  errors: %llu\n",
6691da177e4SLinus Torvalds 		   (unsigned long long)pkt_dev->sofar,
670fd29cf72SStephen Hemminger 		   (unsigned long long)pkt_dev->errors);
671fd29cf72SStephen Hemminger 
672fd29cf72SStephen Hemminger 	seq_printf(seq,
673fd29cf72SStephen Hemminger 		   "     started: %lluus  stopped: %lluus idle: %lluus\n",
674fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(pkt_dev->started_at),
675fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(stopped),
676fd29cf72SStephen Hemminger 		   (unsigned long long) idle);
6771da177e4SLinus Torvalds 
678222f1806SLuiz Capitulino 	seq_printf(seq,
679222f1806SLuiz Capitulino 		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
680d50a6b56SStephen Hemminger 		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
681d50a6b56SStephen Hemminger 		   pkt_dev->cur_src_mac_offset);
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
68447a0200dSAlexey Dobriyan 		seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
68547a0200dSAlexey Dobriyan 				&pkt_dev->cur_in6_saddr,
68647a0200dSAlexey Dobriyan 				&pkt_dev->cur_in6_daddr);
687222f1806SLuiz Capitulino 	} else
6880373a946SAmerigo Wang 		seq_printf(seq, "     cur_saddr: %pI4  cur_daddr: %pI4\n",
6890373a946SAmerigo Wang 			   &pkt_dev->cur_saddr, &pkt_dev->cur_daddr);
6901da177e4SLinus Torvalds 
691d50a6b56SStephen Hemminger 	seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
6921da177e4SLinus Torvalds 		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
6931da177e4SLinus Torvalds 
69445b270f8SRobert Olsson 	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);
69545b270f8SRobert Olsson 
696d50a6b56SStephen Hemminger 	seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	if (pkt_dev->result[0])
699d50a6b56SStephen Hemminger 		seq_printf(seq, "Result: %s\n", pkt_dev->result);
7001da177e4SLinus Torvalds 	else
70197dc48e2SThomas Graf 		seq_puts(seq, "Result: Idle\n");
7021da177e4SLinus Torvalds 
703d50a6b56SStephen Hemminger 	return 0;
7041da177e4SLinus Torvalds }
7051da177e4SLinus Torvalds 
706ca6549afSSteven Whitehouse 
70763adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
70863adc6fbSStephen Hemminger 		     __u32 *num)
709ca6549afSSteven Whitehouse {
710ca6549afSSteven Whitehouse 	int i = 0;
711ca6549afSSteven Whitehouse 	*num = 0;
712ca6549afSSteven Whitehouse 
7131ca7768cSFrancesco Fondelli 	for (; i < maxlen; i++) {
71482fd5b5dSAndy Shevchenko 		int value;
715ca6549afSSteven Whitehouse 		char c;
716ca6549afSSteven Whitehouse 		*num <<= 4;
717ca6549afSSteven Whitehouse 		if (get_user(c, &user_buffer[i]))
718ca6549afSSteven Whitehouse 			return -EFAULT;
71982fd5b5dSAndy Shevchenko 		value = hex_to_bin(c);
72082fd5b5dSAndy Shevchenko 		if (value >= 0)
72182fd5b5dSAndy Shevchenko 			*num |= value;
722ca6549afSSteven Whitehouse 		else
723ca6549afSSteven Whitehouse 			break;
724ca6549afSSteven Whitehouse 	}
725ca6549afSSteven Whitehouse 	return i;
726ca6549afSSteven Whitehouse }
727ca6549afSSteven Whitehouse 
728222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer,
729222f1806SLuiz Capitulino 			     unsigned int maxlen)
7301da177e4SLinus Torvalds {
7311da177e4SLinus Torvalds 	int i;
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 	for (i = 0; i < maxlen; i++) {
7341da177e4SLinus Torvalds 		char c;
7351da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7361da177e4SLinus Torvalds 			return -EFAULT;
7371da177e4SLinus Torvalds 		switch (c) {
7381da177e4SLinus Torvalds 		case '\"':
7391da177e4SLinus Torvalds 		case '\n':
7401da177e4SLinus Torvalds 		case '\r':
7411da177e4SLinus Torvalds 		case '\t':
7421da177e4SLinus Torvalds 		case ' ':
7431da177e4SLinus Torvalds 		case '=':
7441da177e4SLinus Torvalds 			break;
7451da177e4SLinus Torvalds 		default:
7461da177e4SLinus Torvalds 			goto done;
7473ff50b79SStephen Hemminger 		}
7481da177e4SLinus Torvalds 	}
7491da177e4SLinus Torvalds done:
7501da177e4SLinus Torvalds 	return i;
7511da177e4SLinus Torvalds }
7521da177e4SLinus Torvalds 
753bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen,
754bf0813bdSPaul Gortmaker 				unsigned long *num)
7551da177e4SLinus Torvalds {
756d6182223SPaul Gortmaker 	int i;
7571da177e4SLinus Torvalds 	*num = 0;
7581da177e4SLinus Torvalds 
759d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
7601da177e4SLinus Torvalds 		char c;
7611da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7621da177e4SLinus Torvalds 			return -EFAULT;
7631da177e4SLinus Torvalds 		if ((c >= '0') && (c <= '9')) {
7641da177e4SLinus Torvalds 			*num *= 10;
7651da177e4SLinus Torvalds 			*num += c - '0';
7661da177e4SLinus Torvalds 		} else
7671da177e4SLinus Torvalds 			break;
7681da177e4SLinus Torvalds 	}
7691da177e4SLinus Torvalds 	return i;
7701da177e4SLinus Torvalds }
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen)
7731da177e4SLinus Torvalds {
774d6182223SPaul Gortmaker 	int i;
7751da177e4SLinus Torvalds 
776d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
7771da177e4SLinus Torvalds 		char c;
7781da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7791da177e4SLinus Torvalds 			return -EFAULT;
7801da177e4SLinus Torvalds 		switch (c) {
7811da177e4SLinus Torvalds 		case '\"':
7821da177e4SLinus Torvalds 		case '\n':
7831da177e4SLinus Torvalds 		case '\r':
7841da177e4SLinus Torvalds 		case '\t':
7851da177e4SLinus Torvalds 		case ' ':
7861da177e4SLinus Torvalds 			goto done_str;
7871da177e4SLinus Torvalds 		default:
7881da177e4SLinus Torvalds 			break;
7893ff50b79SStephen Hemminger 		}
7901da177e4SLinus Torvalds 	}
7911da177e4SLinus Torvalds done_str:
7921da177e4SLinus Torvalds 	return i;
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds 
795ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
796ca6549afSSteven Whitehouse {
79795c96174SEric Dumazet 	unsigned int n = 0;
798ca6549afSSteven Whitehouse 	char c;
799ca6549afSSteven Whitehouse 	ssize_t i = 0;
800ca6549afSSteven Whitehouse 	int len;
801ca6549afSSteven Whitehouse 
802ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = 0;
803ca6549afSSteven Whitehouse 	do {
804ca6549afSSteven Whitehouse 		__u32 tmp;
8051ca7768cSFrancesco Fondelli 		len = hex32_arg(&buffer[i], 8, &tmp);
806ca6549afSSteven Whitehouse 		if (len <= 0)
807ca6549afSSteven Whitehouse 			return len;
808ca6549afSSteven Whitehouse 		pkt_dev->labels[n] = htonl(tmp);
809ca6549afSSteven Whitehouse 		if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
810ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
811ca6549afSSteven Whitehouse 		i += len;
812ca6549afSSteven Whitehouse 		if (get_user(c, &buffer[i]))
813ca6549afSSteven Whitehouse 			return -EFAULT;
814ca6549afSSteven Whitehouse 		i++;
815ca6549afSSteven Whitehouse 		n++;
816ca6549afSSteven Whitehouse 		if (n >= MAX_MPLS_LABELS)
817ca6549afSSteven Whitehouse 			return -E2BIG;
818ca6549afSSteven Whitehouse 	} while (c == ',');
819ca6549afSSteven Whitehouse 
820ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = n;
821ca6549afSSteven Whitehouse 	return i;
822ca6549afSSteven Whitehouse }
823ca6549afSSteven Whitehouse 
82452e12d5dSDmitry Safonov static __u32 pktgen_read_flag(const char *f, bool *disable)
82552e12d5dSDmitry Safonov {
82652e12d5dSDmitry Safonov 	__u32 i;
82752e12d5dSDmitry Safonov 
82852e12d5dSDmitry Safonov 	if (f[0] == '!') {
82952e12d5dSDmitry Safonov 		*disable = true;
83052e12d5dSDmitry Safonov 		f++;
83152e12d5dSDmitry Safonov 	}
83252e12d5dSDmitry Safonov 
83352e12d5dSDmitry Safonov 	for (i = 0; i < NR_PKT_FLAGS; i++) {
83452e12d5dSDmitry Safonov 		if (!IS_ENABLED(CONFIG_XFRM) && i == IPSEC_SHIFT)
83552e12d5dSDmitry Safonov 			continue;
83652e12d5dSDmitry Safonov 
83752e12d5dSDmitry Safonov 		/* allow only disabling ipv6 flag */
83852e12d5dSDmitry Safonov 		if (!*disable && i == IPV6_SHIFT)
83952e12d5dSDmitry Safonov 			continue;
84052e12d5dSDmitry Safonov 
84152e12d5dSDmitry Safonov 		if (strcmp(f, pkt_flag_names[i]) == 0)
84252e12d5dSDmitry Safonov 			return 1 << i;
84352e12d5dSDmitry Safonov 	}
84452e12d5dSDmitry Safonov 
84552e12d5dSDmitry Safonov 	if (strcmp(f, "FLOW_RND") == 0) {
84652e12d5dSDmitry Safonov 		*disable = !*disable;
84752e12d5dSDmitry Safonov 		return F_FLOW_SEQ;
84852e12d5dSDmitry Safonov 	}
84952e12d5dSDmitry Safonov 
85052e12d5dSDmitry Safonov 	return 0;
85152e12d5dSDmitry Safonov }
85252e12d5dSDmitry Safonov 
853222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file,
854222f1806SLuiz Capitulino 			       const char __user * user_buffer, size_t count,
855222f1806SLuiz Capitulino 			       loff_t * offset)
8561da177e4SLinus Torvalds {
8578a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
858d50a6b56SStephen Hemminger 	struct pktgen_dev *pkt_dev = seq->private;
859d6182223SPaul Gortmaker 	int i, max, len;
8601da177e4SLinus Torvalds 	char name[16], valstr[32];
8611da177e4SLinus Torvalds 	unsigned long value = 0;
8621da177e4SLinus Torvalds 	char *pg_result = NULL;
8631da177e4SLinus Torvalds 	int tmp = 0;
8641da177e4SLinus Torvalds 	char buf[128];
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds 	pg_result = &(pkt_dev->result[0]);
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 	if (count < 1) {
869294a0b7fSJoe Perches 		pr_warn("wrong command format\n");
8701da177e4SLinus Torvalds 		return -EINVAL;
8711da177e4SLinus Torvalds 	}
8721da177e4SLinus Torvalds 
873d6182223SPaul Gortmaker 	max = count;
874d6182223SPaul Gortmaker 	tmp = count_trail_chars(user_buffer, max);
8751da177e4SLinus Torvalds 	if (tmp < 0) {
876294a0b7fSJoe Perches 		pr_warn("illegal format\n");
8771da177e4SLinus Torvalds 		return tmp;
8781da177e4SLinus Torvalds 	}
879d6182223SPaul Gortmaker 	i = tmp;
8801da177e4SLinus Torvalds 
8811da177e4SLinus Torvalds 	/* Read variable name */
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
88463adc6fbSStephen Hemminger 	if (len < 0)
885222f1806SLuiz Capitulino 		return len;
88663adc6fbSStephen Hemminger 
8871da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
8881da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
8891da177e4SLinus Torvalds 		return -EFAULT;
8901da177e4SLinus Torvalds 	i += len;
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds 	max = count - i;
8931da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
8941da177e4SLinus Torvalds 	if (len < 0)
8951da177e4SLinus Torvalds 		return len;
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	i += len;
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	if (debug) {
900a870a02cSArnd Bergmann 		size_t copy = min_t(size_t, count + 1, 1024);
901a870a02cSArnd Bergmann 		char *tp = strndup_user(user_buffer, copy);
902a870a02cSArnd Bergmann 
903a870a02cSArnd Bergmann 		if (IS_ERR(tp))
904a870a02cSArnd Bergmann 			return PTR_ERR(tp);
905a870a02cSArnd Bergmann 
906a870a02cSArnd Bergmann 		pr_debug("%s,%zu  buffer -:%s:-\n", name, count, tp);
90729d1df72SGustavo A. R. Silva 		kfree(tp);
9081da177e4SLinus Torvalds 	}
9091da177e4SLinus Torvalds 
9101da177e4SLinus Torvalds 	if (!strcmp(name, "min_pkt_size")) {
9111da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
91263adc6fbSStephen Hemminger 		if (len < 0)
913222f1806SLuiz Capitulino 			return len;
91463adc6fbSStephen Hemminger 
9151da177e4SLinus Torvalds 		i += len;
9161da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9171da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9181da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9191da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9201da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9211da177e4SLinus Torvalds 		}
92232be425bSYe Bin 		sprintf(pg_result, "OK: min_pkt_size=%d",
923222f1806SLuiz Capitulino 			pkt_dev->min_pkt_size);
9241da177e4SLinus Torvalds 		return count;
9251da177e4SLinus Torvalds 	}
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 	if (!strcmp(name, "max_pkt_size")) {
9281da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
92963adc6fbSStephen Hemminger 		if (len < 0)
930222f1806SLuiz Capitulino 			return len;
93163adc6fbSStephen Hemminger 
9321da177e4SLinus Torvalds 		i += len;
9331da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9341da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9351da177e4SLinus Torvalds 		if (value != pkt_dev->max_pkt_size) {
9361da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9371da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9381da177e4SLinus Torvalds 		}
93932be425bSYe Bin 		sprintf(pg_result, "OK: max_pkt_size=%d",
940222f1806SLuiz Capitulino 			pkt_dev->max_pkt_size);
9411da177e4SLinus Torvalds 		return count;
9421da177e4SLinus Torvalds 	}
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	/* Shortcut for min = max */
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 	if (!strcmp(name, "pkt_size")) {
9471da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
94863adc6fbSStephen Hemminger 		if (len < 0)
949222f1806SLuiz Capitulino 			return len;
95063adc6fbSStephen Hemminger 
9511da177e4SLinus Torvalds 		i += len;
9521da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9531da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9541da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9551da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9561da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9571da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9581da177e4SLinus Torvalds 		}
95932be425bSYe Bin 		sprintf(pg_result, "OK: pkt_size=%d", pkt_dev->min_pkt_size);
9601da177e4SLinus Torvalds 		return count;
9611da177e4SLinus Torvalds 	}
9621da177e4SLinus Torvalds 
9631da177e4SLinus Torvalds 	if (!strcmp(name, "debug")) {
9641da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
96563adc6fbSStephen Hemminger 		if (len < 0)
966222f1806SLuiz Capitulino 			return len;
96763adc6fbSStephen Hemminger 
9681da177e4SLinus Torvalds 		i += len;
9691da177e4SLinus Torvalds 		debug = value;
9701da177e4SLinus Torvalds 		sprintf(pg_result, "OK: debug=%u", debug);
9711da177e4SLinus Torvalds 		return count;
9721da177e4SLinus Torvalds 	}
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds 	if (!strcmp(name, "frags")) {
9751da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
97663adc6fbSStephen Hemminger 		if (len < 0)
977222f1806SLuiz Capitulino 			return len;
97863adc6fbSStephen Hemminger 
9791da177e4SLinus Torvalds 		i += len;
9801da177e4SLinus Torvalds 		pkt_dev->nfrags = value;
98132be425bSYe Bin 		sprintf(pg_result, "OK: frags=%d", pkt_dev->nfrags);
9821da177e4SLinus Torvalds 		return count;
9831da177e4SLinus Torvalds 	}
9841da177e4SLinus Torvalds 	if (!strcmp(name, "delay")) {
9851da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
98663adc6fbSStephen Hemminger 		if (len < 0)
987222f1806SLuiz Capitulino 			return len;
98863adc6fbSStephen Hemminger 
9891da177e4SLinus Torvalds 		i += len;
990fd29cf72SStephen Hemminger 		if (value == 0x7FFFFFFF)
991fd29cf72SStephen Hemminger 			pkt_dev->delay = ULLONG_MAX;
992fd29cf72SStephen Hemminger 		else
9939240d715SEric Dumazet 			pkt_dev->delay = (u64)value;
994fd29cf72SStephen Hemminger 
995fd29cf72SStephen Hemminger 		sprintf(pg_result, "OK: delay=%llu",
996fd29cf72SStephen Hemminger 			(unsigned long long) pkt_dev->delay);
9971da177e4SLinus Torvalds 		return count;
9981da177e4SLinus Torvalds 	}
99943d28b65SDaniel Turull 	if (!strcmp(name, "rate")) {
100043d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
100143d28b65SDaniel Turull 		if (len < 0)
100243d28b65SDaniel Turull 			return len;
100343d28b65SDaniel Turull 
100443d28b65SDaniel Turull 		i += len;
100543d28b65SDaniel Turull 		if (!value)
100643d28b65SDaniel Turull 			return len;
100743d28b65SDaniel Turull 		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
100843d28b65SDaniel Turull 		if (debug)
1009f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
101043d28b65SDaniel Turull 
101143d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
101243d28b65SDaniel Turull 		return count;
101343d28b65SDaniel Turull 	}
101443d28b65SDaniel Turull 	if (!strcmp(name, "ratep")) {
101543d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
101643d28b65SDaniel Turull 		if (len < 0)
101743d28b65SDaniel Turull 			return len;
101843d28b65SDaniel Turull 
101943d28b65SDaniel Turull 		i += len;
102043d28b65SDaniel Turull 		if (!value)
102143d28b65SDaniel Turull 			return len;
102243d28b65SDaniel Turull 		pkt_dev->delay = NSEC_PER_SEC/value;
102343d28b65SDaniel Turull 		if (debug)
1024f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
102543d28b65SDaniel Turull 
102643d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
102743d28b65SDaniel Turull 		return count;
102843d28b65SDaniel Turull 	}
10291da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_min")) {
10301da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
103163adc6fbSStephen Hemminger 		if (len < 0)
1032222f1806SLuiz Capitulino 			return len;
103363adc6fbSStephen Hemminger 
10341da177e4SLinus Torvalds 		i += len;
10351da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_min) {
10361da177e4SLinus Torvalds 			pkt_dev->udp_src_min = value;
10371da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10381da177e4SLinus Torvalds 		}
10391da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
10401da177e4SLinus Torvalds 		return count;
10411da177e4SLinus Torvalds 	}
10421da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_min")) {
10431da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
104463adc6fbSStephen Hemminger 		if (len < 0)
1045222f1806SLuiz Capitulino 			return len;
104663adc6fbSStephen Hemminger 
10471da177e4SLinus Torvalds 		i += len;
10481da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_min) {
10491da177e4SLinus Torvalds 			pkt_dev->udp_dst_min = value;
10501da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10511da177e4SLinus Torvalds 		}
10521da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
10531da177e4SLinus Torvalds 		return count;
10541da177e4SLinus Torvalds 	}
10551da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_max")) {
10561da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
105763adc6fbSStephen Hemminger 		if (len < 0)
1058222f1806SLuiz Capitulino 			return len;
105963adc6fbSStephen Hemminger 
10601da177e4SLinus Torvalds 		i += len;
10611da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_max) {
10621da177e4SLinus Torvalds 			pkt_dev->udp_src_max = value;
10631da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10641da177e4SLinus Torvalds 		}
10651da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
10661da177e4SLinus Torvalds 		return count;
10671da177e4SLinus Torvalds 	}
10681da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_max")) {
10691da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
107063adc6fbSStephen Hemminger 		if (len < 0)
1071222f1806SLuiz Capitulino 			return len;
107263adc6fbSStephen Hemminger 
10731da177e4SLinus Torvalds 		i += len;
10741da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_max) {
10751da177e4SLinus Torvalds 			pkt_dev->udp_dst_max = value;
10761da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10771da177e4SLinus Torvalds 		}
10781da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
10791da177e4SLinus Torvalds 		return count;
10801da177e4SLinus Torvalds 	}
10811da177e4SLinus Torvalds 	if (!strcmp(name, "clone_skb")) {
10821da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
108363adc6fbSStephen Hemminger 		if (len < 0)
1084222f1806SLuiz Capitulino 			return len;
1085d8873315SNeil Horman 		if ((value > 0) &&
108662f64aedSAlexei Starovoitov 		    ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) ||
108762f64aedSAlexei Starovoitov 		     !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
1088d8873315SNeil Horman 			return -ENOTSUPP;
10891da177e4SLinus Torvalds 		i += len;
10901da177e4SLinus Torvalds 		pkt_dev->clone_skb = value;
10911da177e4SLinus Torvalds 
10921da177e4SLinus Torvalds 		sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
10931da177e4SLinus Torvalds 		return count;
10941da177e4SLinus Torvalds 	}
10951da177e4SLinus Torvalds 	if (!strcmp(name, "count")) {
10961da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
109763adc6fbSStephen Hemminger 		if (len < 0)
1098222f1806SLuiz Capitulino 			return len;
109963adc6fbSStephen Hemminger 
11001da177e4SLinus Torvalds 		i += len;
11011da177e4SLinus Torvalds 		pkt_dev->count = value;
11021da177e4SLinus Torvalds 		sprintf(pg_result, "OK: count=%llu",
11031da177e4SLinus Torvalds 			(unsigned long long)pkt_dev->count);
11041da177e4SLinus Torvalds 		return count;
11051da177e4SLinus Torvalds 	}
11061da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac_count")) {
11071da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
110863adc6fbSStephen Hemminger 		if (len < 0)
1109222f1806SLuiz Capitulino 			return len;
111063adc6fbSStephen Hemminger 
11111da177e4SLinus Torvalds 		i += len;
11121da177e4SLinus Torvalds 		if (pkt_dev->src_mac_count != value) {
11131da177e4SLinus Torvalds 			pkt_dev->src_mac_count = value;
11141da177e4SLinus Torvalds 			pkt_dev->cur_src_mac_offset = 0;
11151da177e4SLinus Torvalds 		}
1116222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: src_mac_count=%d",
1117222f1806SLuiz Capitulino 			pkt_dev->src_mac_count);
11181da177e4SLinus Torvalds 		return count;
11191da177e4SLinus Torvalds 	}
11201da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac_count")) {
11211da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
112263adc6fbSStephen Hemminger 		if (len < 0)
1123222f1806SLuiz Capitulino 			return len;
112463adc6fbSStephen Hemminger 
11251da177e4SLinus Torvalds 		i += len;
11261da177e4SLinus Torvalds 		if (pkt_dev->dst_mac_count != value) {
11271da177e4SLinus Torvalds 			pkt_dev->dst_mac_count = value;
11281da177e4SLinus Torvalds 			pkt_dev->cur_dst_mac_offset = 0;
11291da177e4SLinus Torvalds 		}
1130222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: dst_mac_count=%d",
1131222f1806SLuiz Capitulino 			pkt_dev->dst_mac_count);
11321da177e4SLinus Torvalds 		return count;
11331da177e4SLinus Torvalds 	}
113438b2cf29SAlexei Starovoitov 	if (!strcmp(name, "burst")) {
113538b2cf29SAlexei Starovoitov 		len = num_arg(&user_buffer[i], 10, &value);
113638b2cf29SAlexei Starovoitov 		if (len < 0)
113738b2cf29SAlexei Starovoitov 			return len;
113838b2cf29SAlexei Starovoitov 
113938b2cf29SAlexei Starovoitov 		i += len;
11400967f244SJohn Fastabend 		if ((value > 1) &&
11410967f244SJohn Fastabend 		    ((pkt_dev->xmit_mode == M_QUEUE_XMIT) ||
11420967f244SJohn Fastabend 		     ((pkt_dev->xmit_mode == M_START_XMIT) &&
11430967f244SJohn Fastabend 		     (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))))
114452d6c8c6SEric Dumazet 			return -ENOTSUPP;
114538b2cf29SAlexei Starovoitov 		pkt_dev->burst = value < 1 ? 1 : value;
114632be425bSYe Bin 		sprintf(pg_result, "OK: burst=%u", pkt_dev->burst);
114738b2cf29SAlexei Starovoitov 		return count;
114838b2cf29SAlexei Starovoitov 	}
1149e99b99b4SRobert Olsson 	if (!strcmp(name, "node")) {
1150e99b99b4SRobert Olsson 		len = num_arg(&user_buffer[i], 10, &value);
1151e99b99b4SRobert Olsson 		if (len < 0)
1152e99b99b4SRobert Olsson 			return len;
1153e99b99b4SRobert Olsson 
1154e99b99b4SRobert Olsson 		i += len;
1155e99b99b4SRobert Olsson 
1156e99b99b4SRobert Olsson 		if (node_possible(value)) {
1157e99b99b4SRobert Olsson 			pkt_dev->node = value;
1158e99b99b4SRobert Olsson 			sprintf(pg_result, "OK: node=%d", pkt_dev->node);
115926ad7879SEric Dumazet 			if (pkt_dev->page) {
116026ad7879SEric Dumazet 				put_page(pkt_dev->page);
116126ad7879SEric Dumazet 				pkt_dev->page = NULL;
116226ad7879SEric Dumazet 			}
1163e99b99b4SRobert Olsson 		}
1164e99b99b4SRobert Olsson 		else
1165e99b99b4SRobert Olsson 			sprintf(pg_result, "ERROR: node not possible");
1166e99b99b4SRobert Olsson 		return count;
1167e99b99b4SRobert Olsson 	}
116862f64aedSAlexei Starovoitov 	if (!strcmp(name, "xmit_mode")) {
116962f64aedSAlexei Starovoitov 		char f[32];
117062f64aedSAlexei Starovoitov 
117162f64aedSAlexei Starovoitov 		memset(f, 0, 32);
117262f64aedSAlexei Starovoitov 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
117362f64aedSAlexei Starovoitov 		if (len < 0)
117462f64aedSAlexei Starovoitov 			return len;
117562f64aedSAlexei Starovoitov 
117662f64aedSAlexei Starovoitov 		if (copy_from_user(f, &user_buffer[i], len))
117762f64aedSAlexei Starovoitov 			return -EFAULT;
117862f64aedSAlexei Starovoitov 		i += len;
117962f64aedSAlexei Starovoitov 
118062f64aedSAlexei Starovoitov 		if (strcmp(f, "start_xmit") == 0) {
118162f64aedSAlexei Starovoitov 			pkt_dev->xmit_mode = M_START_XMIT;
118262f64aedSAlexei Starovoitov 		} else if (strcmp(f, "netif_receive") == 0) {
118362f64aedSAlexei Starovoitov 			/* clone_skb set earlier, not supported in this mode */
118462f64aedSAlexei Starovoitov 			if (pkt_dev->clone_skb > 0)
118562f64aedSAlexei Starovoitov 				return -ENOTSUPP;
118662f64aedSAlexei Starovoitov 
118762f64aedSAlexei Starovoitov 			pkt_dev->xmit_mode = M_NETIF_RECEIVE;
11889eea9222SAlexei Starovoitov 
11899eea9222SAlexei Starovoitov 			/* make sure new packet is allocated every time
11909eea9222SAlexei Starovoitov 			 * pktgen_xmit() is called
11919eea9222SAlexei Starovoitov 			 */
11929eea9222SAlexei Starovoitov 			pkt_dev->last_ok = 1;
11939eea9222SAlexei Starovoitov 
11949eea9222SAlexei Starovoitov 			/* override clone_skb if user passed default value
11959eea9222SAlexei Starovoitov 			 * at module loading time
11969eea9222SAlexei Starovoitov 			 */
11979eea9222SAlexei Starovoitov 			pkt_dev->clone_skb = 0;
11980967f244SJohn Fastabend 		} else if (strcmp(f, "queue_xmit") == 0) {
11990967f244SJohn Fastabend 			pkt_dev->xmit_mode = M_QUEUE_XMIT;
12000967f244SJohn Fastabend 			pkt_dev->last_ok = 1;
120162f64aedSAlexei Starovoitov 		} else {
120262f64aedSAlexei Starovoitov 			sprintf(pg_result,
120362f64aedSAlexei Starovoitov 				"xmit_mode -:%s:- unknown\nAvailable modes: %s",
120462f64aedSAlexei Starovoitov 				f, "start_xmit, netif_receive\n");
120562f64aedSAlexei Starovoitov 			return count;
120662f64aedSAlexei Starovoitov 		}
120762f64aedSAlexei Starovoitov 		sprintf(pg_result, "OK: xmit_mode=%s", f);
120862f64aedSAlexei Starovoitov 		return count;
120962f64aedSAlexei Starovoitov 	}
12101da177e4SLinus Torvalds 	if (!strcmp(name, "flag")) {
121152e12d5dSDmitry Safonov 		__u32 flag;
12121da177e4SLinus Torvalds 		char f[32];
121352e12d5dSDmitry Safonov 		bool disable = false;
121452e12d5dSDmitry Safonov 
12151da177e4SLinus Torvalds 		memset(f, 0, 32);
12161da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
121763adc6fbSStephen Hemminger 		if (len < 0)
1218222f1806SLuiz Capitulino 			return len;
121963adc6fbSStephen Hemminger 
12201da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
12211da177e4SLinus Torvalds 			return -EFAULT;
12221da177e4SLinus Torvalds 		i += len;
12231da177e4SLinus Torvalds 
122452e12d5dSDmitry Safonov 		flag = pktgen_read_flag(f, &disable);
12251da177e4SLinus Torvalds 
122652e12d5dSDmitry Safonov 		if (flag) {
122752e12d5dSDmitry Safonov 			if (disable)
122852e12d5dSDmitry Safonov 				pkt_dev->flags &= ~flag;
122952e12d5dSDmitry Safonov 			else
123052e12d5dSDmitry Safonov 				pkt_dev->flags |= flag;
123152e12d5dSDmitry Safonov 		} else {
1232222f1806SLuiz Capitulino 			sprintf(pg_result,
1233222f1806SLuiz Capitulino 				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
12341da177e4SLinus Torvalds 				f,
12351ca7768cSFrancesco Fondelli 				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
123672f8e06fSMathias Krause 				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
123772f8e06fSMathias Krause 				"MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
123872f8e06fSMathias Krause 				"QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
1239afb84b62SJesper Dangaard Brouer 				"NO_TIMESTAMP, "
124072f8e06fSMathias Krause #ifdef CONFIG_XFRM
124172f8e06fSMathias Krause 				"IPSEC, "
124272f8e06fSMathias Krause #endif
124372f8e06fSMathias Krause 				"NODE_ALLOC\n");
12441da177e4SLinus Torvalds 			return count;
12451da177e4SLinus Torvalds 		}
12461da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
12471da177e4SLinus Torvalds 		return count;
12481da177e4SLinus Torvalds 	}
12491da177e4SLinus Torvalds 	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
12501da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
125163adc6fbSStephen Hemminger 		if (len < 0)
1252222f1806SLuiz Capitulino 			return len;
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12551da177e4SLinus Torvalds 			return -EFAULT;
12561da177e4SLinus Torvalds 		buf[len] = 0;
12571da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_min) != 0) {
12581da177e4SLinus Torvalds 			memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
1259f15f084fSJakub Kicinski 			strcpy(pkt_dev->dst_min, buf);
12601da177e4SLinus Torvalds 			pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
12611da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_min;
12621da177e4SLinus Torvalds 		}
12631da177e4SLinus Torvalds 		if (debug)
1264f342cda7SJoe Perches 			pr_debug("dst_min set to: %s\n", pkt_dev->dst_min);
12651da177e4SLinus Torvalds 		i += len;
12661da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
12671da177e4SLinus Torvalds 		return count;
12681da177e4SLinus Torvalds 	}
12691da177e4SLinus Torvalds 	if (!strcmp(name, "dst_max")) {
12701da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
127163adc6fbSStephen Hemminger 		if (len < 0)
1272222f1806SLuiz Capitulino 			return len;
127363adc6fbSStephen Hemminger 
12741da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12751da177e4SLinus Torvalds 			return -EFAULT;
12761da177e4SLinus Torvalds 		buf[len] = 0;
12771da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_max) != 0) {
12781da177e4SLinus Torvalds 			memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
1279f15f084fSJakub Kicinski 			strcpy(pkt_dev->dst_max, buf);
12801da177e4SLinus Torvalds 			pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
12811da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_max;
12821da177e4SLinus Torvalds 		}
12831da177e4SLinus Torvalds 		if (debug)
1284f342cda7SJoe Perches 			pr_debug("dst_max set to: %s\n", pkt_dev->dst_max);
12851da177e4SLinus Torvalds 		i += len;
12861da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
12871da177e4SLinus Torvalds 		return count;
12881da177e4SLinus Torvalds 	}
12891da177e4SLinus Torvalds 	if (!strcmp(name, "dst6")) {
12901da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1291222f1806SLuiz Capitulino 		if (len < 0)
1292222f1806SLuiz Capitulino 			return len;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12971da177e4SLinus Torvalds 			return -EFAULT;
12981da177e4SLinus Torvalds 		buf[len] = 0;
12991da177e4SLinus Torvalds 
1300c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL);
130147a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
13021da177e4SLinus Torvalds 
13034e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr;
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 		if (debug)
1306f342cda7SJoe Perches 			pr_debug("dst6 set to: %s\n", buf);
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 		i += len;
13091da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6=%s", buf);
13101da177e4SLinus Torvalds 		return count;
13111da177e4SLinus Torvalds 	}
13121da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_min")) {
13131da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1314222f1806SLuiz Capitulino 		if (len < 0)
1315222f1806SLuiz Capitulino 			return len;
13161da177e4SLinus Torvalds 
13171da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13201da177e4SLinus Torvalds 			return -EFAULT;
13211da177e4SLinus Torvalds 		buf[len] = 0;
13221da177e4SLinus Torvalds 
1323c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL);
132447a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
13251da177e4SLinus Torvalds 
13264e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr;
13271da177e4SLinus Torvalds 		if (debug)
1328f342cda7SJoe Perches 			pr_debug("dst6_min set to: %s\n", buf);
13291da177e4SLinus Torvalds 
13301da177e4SLinus Torvalds 		i += len;
13311da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_min=%s", buf);
13321da177e4SLinus Torvalds 		return count;
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_max")) {
13351da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1336222f1806SLuiz Capitulino 		if (len < 0)
1337222f1806SLuiz Capitulino 			return len;
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13421da177e4SLinus Torvalds 			return -EFAULT;
13431da177e4SLinus Torvalds 		buf[len] = 0;
13441da177e4SLinus Torvalds 
1345c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL);
134647a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 		if (debug)
1349f342cda7SJoe Perches 			pr_debug("dst6_max set to: %s\n", buf);
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds 		i += len;
13521da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_max=%s", buf);
13531da177e4SLinus Torvalds 		return count;
13541da177e4SLinus Torvalds 	}
13551da177e4SLinus Torvalds 	if (!strcmp(name, "src6")) {
13561da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1357222f1806SLuiz Capitulino 		if (len < 0)
1358222f1806SLuiz Capitulino 			return len;
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13631da177e4SLinus Torvalds 			return -EFAULT;
13641da177e4SLinus Torvalds 		buf[len] = 0;
13651da177e4SLinus Torvalds 
1366c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL);
136747a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
13681da177e4SLinus Torvalds 
13694e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr;
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds 		if (debug)
1372f342cda7SJoe Perches 			pr_debug("src6 set to: %s\n", buf);
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds 		i += len;
13751da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src6=%s", buf);
13761da177e4SLinus Torvalds 		return count;
13771da177e4SLinus Torvalds 	}
13781da177e4SLinus Torvalds 	if (!strcmp(name, "src_min")) {
13791da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
138063adc6fbSStephen Hemminger 		if (len < 0)
1381222f1806SLuiz Capitulino 			return len;
138263adc6fbSStephen Hemminger 
13831da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13841da177e4SLinus Torvalds 			return -EFAULT;
13851da177e4SLinus Torvalds 		buf[len] = 0;
13861da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_min) != 0) {
13871da177e4SLinus Torvalds 			memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
1388f15f084fSJakub Kicinski 			strcpy(pkt_dev->src_min, buf);
13891da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
13901da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_min;
13911da177e4SLinus Torvalds 		}
13921da177e4SLinus Torvalds 		if (debug)
1393f342cda7SJoe Perches 			pr_debug("src_min set to: %s\n", pkt_dev->src_min);
13941da177e4SLinus Torvalds 		i += len;
13951da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
13961da177e4SLinus Torvalds 		return count;
13971da177e4SLinus Torvalds 	}
13981da177e4SLinus Torvalds 	if (!strcmp(name, "src_max")) {
13991da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
140063adc6fbSStephen Hemminger 		if (len < 0)
1401222f1806SLuiz Capitulino 			return len;
140263adc6fbSStephen Hemminger 
14031da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14041da177e4SLinus Torvalds 			return -EFAULT;
14051da177e4SLinus Torvalds 		buf[len] = 0;
14061da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_max) != 0) {
14071da177e4SLinus Torvalds 			memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
1408f15f084fSJakub Kicinski 			strcpy(pkt_dev->src_max, buf);
14091da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
14101da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_max;
14111da177e4SLinus Torvalds 		}
14121da177e4SLinus Torvalds 		if (debug)
1413f342cda7SJoe Perches 			pr_debug("src_max set to: %s\n", pkt_dev->src_max);
14141da177e4SLinus Torvalds 		i += len;
14151da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
14161da177e4SLinus Torvalds 		return count;
14171da177e4SLinus Torvalds 	}
14181da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac")) {
14191da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
142063adc6fbSStephen Hemminger 		if (len < 0)
1421222f1806SLuiz Capitulino 			return len;
142263adc6fbSStephen Hemminger 
14231da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
14241da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
14251da177e4SLinus Torvalds 			return -EFAULT;
14261da177e4SLinus Torvalds 
14274940fc88SAlexey Dobriyan 		if (!mac_pton(valstr, pkt_dev->dst_mac))
14284940fc88SAlexey Dobriyan 			return -EINVAL;
14291da177e4SLinus Torvalds 		/* Set up Dest MAC */
14309ea08b12SJoe Perches 		ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac);
14311da177e4SLinus Torvalds 
14324940fc88SAlexey Dobriyan 		sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
14331da177e4SLinus Torvalds 		return count;
14341da177e4SLinus Torvalds 	}
14351da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac")) {
14361da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
143763adc6fbSStephen Hemminger 		if (len < 0)
1438222f1806SLuiz Capitulino 			return len;
143963adc6fbSStephen Hemminger 
14401da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
14411da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
14421da177e4SLinus Torvalds 			return -EFAULT;
14431da177e4SLinus Torvalds 
14444940fc88SAlexey Dobriyan 		if (!mac_pton(valstr, pkt_dev->src_mac))
14454940fc88SAlexey Dobriyan 			return -EINVAL;
1446ce5d0b47SAdit Ranadive 		/* Set up Src MAC */
14479ea08b12SJoe Perches 		ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac);
1448ce5d0b47SAdit Ranadive 
14494940fc88SAlexey Dobriyan 		sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
14501da177e4SLinus Torvalds 		return count;
14511da177e4SLinus Torvalds 	}
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 	if (!strcmp(name, "clear_counters")) {
14541da177e4SLinus Torvalds 		pktgen_clear_counters(pkt_dev);
14551da177e4SLinus Torvalds 		sprintf(pg_result, "OK: Clearing counters.\n");
14561da177e4SLinus Torvalds 		return count;
14571da177e4SLinus Torvalds 	}
14581da177e4SLinus Torvalds 
14591da177e4SLinus Torvalds 	if (!strcmp(name, "flows")) {
14601da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
146163adc6fbSStephen Hemminger 		if (len < 0)
1462222f1806SLuiz Capitulino 			return len;
146363adc6fbSStephen Hemminger 
14641da177e4SLinus Torvalds 		i += len;
14651da177e4SLinus Torvalds 		if (value > MAX_CFLOWS)
14661da177e4SLinus Torvalds 			value = MAX_CFLOWS;
14671da177e4SLinus Torvalds 
14681da177e4SLinus Torvalds 		pkt_dev->cflows = value;
14691da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
14701da177e4SLinus Torvalds 		return count;
14711da177e4SLinus Torvalds 	}
14726bae9190SFan Du #ifdef CONFIG_XFRM
1473de4aee7dSFan Du 	if (!strcmp(name, "spi")) {
1474de4aee7dSFan Du 		len = num_arg(&user_buffer[i], 10, &value);
1475de4aee7dSFan Du 		if (len < 0)
1476de4aee7dSFan Du 			return len;
1477de4aee7dSFan Du 
1478de4aee7dSFan Du 		i += len;
1479de4aee7dSFan Du 		pkt_dev->spi = value;
1480de4aee7dSFan Du 		sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
1481de4aee7dSFan Du 		return count;
1482de4aee7dSFan Du 	}
14836bae9190SFan Du #endif
14841da177e4SLinus Torvalds 	if (!strcmp(name, "flowlen")) {
14851da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
148663adc6fbSStephen Hemminger 		if (len < 0)
1487222f1806SLuiz Capitulino 			return len;
148863adc6fbSStephen Hemminger 
14891da177e4SLinus Torvalds 		i += len;
14901da177e4SLinus Torvalds 		pkt_dev->lflow = value;
14911da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
14921da177e4SLinus Torvalds 		return count;
14931da177e4SLinus Torvalds 	}
14941da177e4SLinus Torvalds 
149545b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_min")) {
149645b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
149763adc6fbSStephen Hemminger 		if (len < 0)
149845b270f8SRobert Olsson 			return len;
149963adc6fbSStephen Hemminger 
150045b270f8SRobert Olsson 		i += len;
150145b270f8SRobert Olsson 		pkt_dev->queue_map_min = value;
150245b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
150345b270f8SRobert Olsson 		return count;
150445b270f8SRobert Olsson 	}
150545b270f8SRobert Olsson 
150645b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_max")) {
150745b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
150863adc6fbSStephen Hemminger 		if (len < 0)
150945b270f8SRobert Olsson 			return len;
151063adc6fbSStephen Hemminger 
151145b270f8SRobert Olsson 		i += len;
151245b270f8SRobert Olsson 		pkt_dev->queue_map_max = value;
151345b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
151445b270f8SRobert Olsson 		return count;
151545b270f8SRobert Olsson 	}
151645b270f8SRobert Olsson 
1517ca6549afSSteven Whitehouse 	if (!strcmp(name, "mpls")) {
151895c96174SEric Dumazet 		unsigned int n, cnt;
1519cfcabdccSStephen Hemminger 
1520ca6549afSSteven Whitehouse 		len = get_labels(&user_buffer[i], pkt_dev);
1521cfcabdccSStephen Hemminger 		if (len < 0)
1522cfcabdccSStephen Hemminger 			return len;
1523ca6549afSSteven Whitehouse 		i += len;
1524cfcabdccSStephen Hemminger 		cnt = sprintf(pg_result, "OK: mpls=");
1525ca6549afSSteven Whitehouse 		for (n = 0; n < pkt_dev->nr_labels; n++)
1526cfcabdccSStephen Hemminger 			cnt += sprintf(pg_result + cnt,
1527ca6549afSSteven Whitehouse 				       "%08x%s", ntohl(pkt_dev->labels[n]),
1528ca6549afSSteven Whitehouse 				       n == pkt_dev->nr_labels-1 ? "" : ",");
152934954ddcSFrancesco Fondelli 
153034954ddcSFrancesco Fondelli 		if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
153134954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
153234954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
153334954ddcSFrancesco Fondelli 
153434954ddcSFrancesco Fondelli 			if (debug)
1535f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN auto turned off\n");
153634954ddcSFrancesco Fondelli 		}
153734954ddcSFrancesco Fondelli 		return count;
153834954ddcSFrancesco Fondelli 	}
153934954ddcSFrancesco Fondelli 
154034954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_id")) {
154134954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
154263adc6fbSStephen Hemminger 		if (len < 0)
154334954ddcSFrancesco Fondelli 			return len;
154463adc6fbSStephen Hemminger 
154534954ddcSFrancesco Fondelli 		i += len;
154634954ddcSFrancesco Fondelli 		if (value <= 4095) {
154734954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = value;  /* turn on VLAN */
154834954ddcSFrancesco Fondelli 
154934954ddcSFrancesco Fondelli 			if (debug)
1550f342cda7SJoe Perches 				pr_debug("VLAN turned on\n");
155134954ddcSFrancesco Fondelli 
155234954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
1553f342cda7SJoe Perches 				pr_debug("MPLS auto turned off\n");
155434954ddcSFrancesco Fondelli 
155534954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
155634954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
155734954ddcSFrancesco Fondelli 		} else {
155834954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
155934954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
156034954ddcSFrancesco Fondelli 
156134954ddcSFrancesco Fondelli 			if (debug)
1562f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN turned off\n");
156334954ddcSFrancesco Fondelli 		}
156434954ddcSFrancesco Fondelli 		return count;
156534954ddcSFrancesco Fondelli 	}
156634954ddcSFrancesco Fondelli 
156734954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_p")) {
156834954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
156963adc6fbSStephen Hemminger 		if (len < 0)
157034954ddcSFrancesco Fondelli 			return len;
157163adc6fbSStephen Hemminger 
157234954ddcSFrancesco Fondelli 		i += len;
157334954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
157434954ddcSFrancesco Fondelli 			pkt_dev->vlan_p = value;
157534954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
157634954ddcSFrancesco Fondelli 		} else {
157734954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_p must be 0-7");
157834954ddcSFrancesco Fondelli 		}
157934954ddcSFrancesco Fondelli 		return count;
158034954ddcSFrancesco Fondelli 	}
158134954ddcSFrancesco Fondelli 
158234954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_cfi")) {
158334954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
158463adc6fbSStephen Hemminger 		if (len < 0)
158534954ddcSFrancesco Fondelli 			return len;
158663adc6fbSStephen Hemminger 
158734954ddcSFrancesco Fondelli 		i += len;
158834954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
158934954ddcSFrancesco Fondelli 			pkt_dev->vlan_cfi = value;
159034954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
159134954ddcSFrancesco Fondelli 		} else {
159234954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
159334954ddcSFrancesco Fondelli 		}
159434954ddcSFrancesco Fondelli 		return count;
159534954ddcSFrancesco Fondelli 	}
159634954ddcSFrancesco Fondelli 
159734954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_id")) {
159834954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
159963adc6fbSStephen Hemminger 		if (len < 0)
160034954ddcSFrancesco Fondelli 			return len;
160163adc6fbSStephen Hemminger 
160234954ddcSFrancesco Fondelli 		i += len;
160334954ddcSFrancesco Fondelli 		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
160434954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = value;  /* turn on SVLAN */
160534954ddcSFrancesco Fondelli 
160634954ddcSFrancesco Fondelli 			if (debug)
1607f342cda7SJoe Perches 				pr_debug("SVLAN turned on\n");
160834954ddcSFrancesco Fondelli 
160934954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
1610f342cda7SJoe Perches 				pr_debug("MPLS auto turned off\n");
161134954ddcSFrancesco Fondelli 
161234954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
161334954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
161434954ddcSFrancesco Fondelli 		} else {
161534954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
161634954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
161734954ddcSFrancesco Fondelli 
161834954ddcSFrancesco Fondelli 			if (debug)
1619f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN turned off\n");
162034954ddcSFrancesco Fondelli 		}
162134954ddcSFrancesco Fondelli 		return count;
162234954ddcSFrancesco Fondelli 	}
162334954ddcSFrancesco Fondelli 
162434954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_p")) {
162534954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
162663adc6fbSStephen Hemminger 		if (len < 0)
162734954ddcSFrancesco Fondelli 			return len;
162863adc6fbSStephen Hemminger 
162934954ddcSFrancesco Fondelli 		i += len;
163034954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
163134954ddcSFrancesco Fondelli 			pkt_dev->svlan_p = value;
163234954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
163334954ddcSFrancesco Fondelli 		} else {
163434954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_p must be 0-7");
163534954ddcSFrancesco Fondelli 		}
163634954ddcSFrancesco Fondelli 		return count;
163734954ddcSFrancesco Fondelli 	}
163834954ddcSFrancesco Fondelli 
163934954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_cfi")) {
164034954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
164163adc6fbSStephen Hemminger 		if (len < 0)
164234954ddcSFrancesco Fondelli 			return len;
164363adc6fbSStephen Hemminger 
164434954ddcSFrancesco Fondelli 		i += len;
164534954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
164634954ddcSFrancesco Fondelli 			pkt_dev->svlan_cfi = value;
164734954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
164834954ddcSFrancesco Fondelli 		} else {
164934954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
165034954ddcSFrancesco Fondelli 		}
1651ca6549afSSteven Whitehouse 		return count;
1652ca6549afSSteven Whitehouse 	}
1653ca6549afSSteven Whitehouse 
16541ca7768cSFrancesco Fondelli 	if (!strcmp(name, "tos")) {
16551ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
16561ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
165763adc6fbSStephen Hemminger 		if (len < 0)
16581ca7768cSFrancesco Fondelli 			return len;
165963adc6fbSStephen Hemminger 
16601ca7768cSFrancesco Fondelli 		i += len;
16611ca7768cSFrancesco Fondelli 		if (len == 2) {
16621ca7768cSFrancesco Fondelli 			pkt_dev->tos = tmp_value;
16631ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
16641ca7768cSFrancesco Fondelli 		} else {
16651ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: tos must be 00-ff");
16661ca7768cSFrancesco Fondelli 		}
16671ca7768cSFrancesco Fondelli 		return count;
16681ca7768cSFrancesco Fondelli 	}
16691ca7768cSFrancesco Fondelli 
16701ca7768cSFrancesco Fondelli 	if (!strcmp(name, "traffic_class")) {
16711ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
16721ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
167363adc6fbSStephen Hemminger 		if (len < 0)
16741ca7768cSFrancesco Fondelli 			return len;
167563adc6fbSStephen Hemminger 
16761ca7768cSFrancesco Fondelli 		i += len;
16771ca7768cSFrancesco Fondelli 		if (len == 2) {
16781ca7768cSFrancesco Fondelli 			pkt_dev->traffic_class = tmp_value;
16791ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
16801ca7768cSFrancesco Fondelli 		} else {
16811ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
16821ca7768cSFrancesco Fondelli 		}
16831ca7768cSFrancesco Fondelli 		return count;
16841ca7768cSFrancesco Fondelli 	}
16851ca7768cSFrancesco Fondelli 
16869e50e3acSJohn Fastabend 	if (!strcmp(name, "skb_priority")) {
16879e50e3acSJohn Fastabend 		len = num_arg(&user_buffer[i], 9, &value);
16889e50e3acSJohn Fastabend 		if (len < 0)
16899e50e3acSJohn Fastabend 			return len;
16909e50e3acSJohn Fastabend 
16919e50e3acSJohn Fastabend 		i += len;
16929e50e3acSJohn Fastabend 		pkt_dev->skb_priority = value;
16939e50e3acSJohn Fastabend 		sprintf(pg_result, "OK: skb_priority=%i",
16949e50e3acSJohn Fastabend 			pkt_dev->skb_priority);
16959e50e3acSJohn Fastabend 		return count;
16969e50e3acSJohn Fastabend 	}
16979e50e3acSJohn Fastabend 
16981da177e4SLinus Torvalds 	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
16991da177e4SLinus Torvalds 	return -EINVAL;
17001da177e4SLinus Torvalds }
17011da177e4SLinus Torvalds 
1702d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file)
17031da177e4SLinus Torvalds {
1704d9dda78bSAl Viro 	return single_open(file, pktgen_if_show, PDE_DATA(inode));
17051da177e4SLinus Torvalds }
17061da177e4SLinus Torvalds 
170797a32539SAlexey Dobriyan static const struct proc_ops pktgen_if_proc_ops = {
170897a32539SAlexey Dobriyan 	.proc_open	= pktgen_if_open,
170997a32539SAlexey Dobriyan 	.proc_read	= seq_read,
171097a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
171197a32539SAlexey Dobriyan 	.proc_write	= pktgen_if_write,
171297a32539SAlexey Dobriyan 	.proc_release	= single_release,
1713d50a6b56SStephen Hemminger };
1714d50a6b56SStephen Hemminger 
1715d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v)
1716d50a6b56SStephen Hemminger {
1717d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1718648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
1719d50a6b56SStephen Hemminger 
1720d50a6b56SStephen Hemminger 	BUG_ON(!t);
1721d50a6b56SStephen Hemminger 
172297dc48e2SThomas Graf 	seq_puts(seq, "Running: ");
17231da177e4SLinus Torvalds 
17248788370aSJesper Dangaard Brouer 	rcu_read_lock();
17258788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
17261da177e4SLinus Torvalds 		if (pkt_dev->running)
1727593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
17281da177e4SLinus Torvalds 
172997dc48e2SThomas Graf 	seq_puts(seq, "\nStopped: ");
17301da177e4SLinus Torvalds 
17318788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
17321da177e4SLinus Torvalds 		if (!pkt_dev->running)
1733593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 	if (t->result[0])
1736d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: %s\n", t->result);
17371da177e4SLinus Torvalds 	else
173897dc48e2SThomas Graf 		seq_puts(seq, "\nResult: NA\n");
17391da177e4SLinus Torvalds 
17408788370aSJesper Dangaard Brouer 	rcu_read_unlock();
17411da177e4SLinus Torvalds 
1742d50a6b56SStephen Hemminger 	return 0;
17431da177e4SLinus Torvalds }
17441da177e4SLinus Torvalds 
1745d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file,
1746d50a6b56SStephen Hemminger 				   const char __user * user_buffer,
1747d50a6b56SStephen Hemminger 				   size_t count, loff_t * offset)
17481da177e4SLinus Torvalds {
17498a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
1750d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1751d6182223SPaul Gortmaker 	int i, max, len, ret;
17521da177e4SLinus Torvalds 	char name[40];
17531da177e4SLinus Torvalds 	char *pg_result;
17541da177e4SLinus Torvalds 
17551da177e4SLinus Torvalds 	if (count < 1) {
17561da177e4SLinus Torvalds 		//      sprintf(pg_result, "Wrong command format");
17571da177e4SLinus Torvalds 		return -EINVAL;
17581da177e4SLinus Torvalds 	}
17591da177e4SLinus Torvalds 
1760d6182223SPaul Gortmaker 	max = count;
1761d6182223SPaul Gortmaker 	len = count_trail_chars(user_buffer, max);
17621da177e4SLinus Torvalds 	if (len < 0)
17631da177e4SLinus Torvalds 		return len;
17641da177e4SLinus Torvalds 
1765d6182223SPaul Gortmaker 	i = len;
17661da177e4SLinus Torvalds 
17671da177e4SLinus Torvalds 	/* Read variable name */
17681da177e4SLinus Torvalds 
17691da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
17701da177e4SLinus Torvalds 	if (len < 0)
17711da177e4SLinus Torvalds 		return len;
17721da177e4SLinus Torvalds 
17731da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
17741da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
17751da177e4SLinus Torvalds 		return -EFAULT;
17761da177e4SLinus Torvalds 	i += len;
17771da177e4SLinus Torvalds 
17781da177e4SLinus Torvalds 	max = count - i;
17791da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
17801da177e4SLinus Torvalds 	if (len < 0)
17811da177e4SLinus Torvalds 		return len;
17821da177e4SLinus Torvalds 
17831da177e4SLinus Torvalds 	i += len;
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds 	if (debug)
1786f342cda7SJoe Perches 		pr_debug("t=%s, count=%lu\n", name, (unsigned long)count);
17871da177e4SLinus Torvalds 
17881da177e4SLinus Torvalds 	if (!t) {
1789f9467eaeSJoe Perches 		pr_err("ERROR: No thread\n");
17901da177e4SLinus Torvalds 		ret = -EINVAL;
17911da177e4SLinus Torvalds 		goto out;
17921da177e4SLinus Torvalds 	}
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds 	pg_result = &(t->result[0]);
17951da177e4SLinus Torvalds 
17961da177e4SLinus Torvalds 	if (!strcmp(name, "add_device")) {
17971da177e4SLinus Torvalds 		char f[32];
17981da177e4SLinus Torvalds 		memset(f, 0, 32);
17991da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
18001da177e4SLinus Torvalds 		if (len < 0) {
18011da177e4SLinus Torvalds 			ret = len;
18021da177e4SLinus Torvalds 			goto out;
18031da177e4SLinus Torvalds 		}
18041da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
18051da177e4SLinus Torvalds 			return -EFAULT;
18061da177e4SLinus Torvalds 		i += len;
18076146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
1808604dfd6eSCong Wang 		ret = pktgen_add_device(t, f);
18096146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1810604dfd6eSCong Wang 		if (!ret) {
18111da177e4SLinus Torvalds 			ret = count;
18121da177e4SLinus Torvalds 			sprintf(pg_result, "OK: add_device=%s", f);
1813604dfd6eSCong Wang 		} else
1814604dfd6eSCong Wang 			sprintf(pg_result, "ERROR: can not add device %s", f);
18151da177e4SLinus Torvalds 		goto out;
18161da177e4SLinus Torvalds 	}
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds 	if (!strcmp(name, "rem_device_all")) {
18196146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
182095ed63f7SArthur Kepner 		t->control |= T_REMDEVALL;
18216146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1822121caf57SNishanth Aravamudan 		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
18231da177e4SLinus Torvalds 		ret = count;
18241da177e4SLinus Torvalds 		sprintf(pg_result, "OK: rem_device_all");
18251da177e4SLinus Torvalds 		goto out;
18261da177e4SLinus Torvalds 	}
18271da177e4SLinus Torvalds 
18281da177e4SLinus Torvalds 	if (!strcmp(name, "max_before_softirq")) {
1829b163911fSRobert Olsson 		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
18301da177e4SLinus Torvalds 		ret = count;
18311da177e4SLinus Torvalds 		goto out;
18321da177e4SLinus Torvalds 	}
18331da177e4SLinus Torvalds 
18341da177e4SLinus Torvalds 	ret = -EINVAL;
18351da177e4SLinus Torvalds out:
18361da177e4SLinus Torvalds 	return ret;
18371da177e4SLinus Torvalds }
18381da177e4SLinus Torvalds 
1839d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file)
18401da177e4SLinus Torvalds {
1841d9dda78bSAl Viro 	return single_open(file, pktgen_thread_show, PDE_DATA(inode));
18421da177e4SLinus Torvalds }
18431da177e4SLinus Torvalds 
184497a32539SAlexey Dobriyan static const struct proc_ops pktgen_thread_proc_ops = {
184597a32539SAlexey Dobriyan 	.proc_open	= pktgen_thread_open,
184697a32539SAlexey Dobriyan 	.proc_read	= seq_read,
184797a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
184897a32539SAlexey Dobriyan 	.proc_write	= pktgen_thread_write,
184997a32539SAlexey Dobriyan 	.proc_release	= single_release,
1850d50a6b56SStephen Hemminger };
18511da177e4SLinus Torvalds 
18521da177e4SLinus Torvalds /* Think find or remove for NN */
18534e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn,
18544e58a027SCong Wang 					      const char *ifname, int remove)
18551da177e4SLinus Torvalds {
18561da177e4SLinus Torvalds 	struct pktgen_thread *t;
18571da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
18583e984840SEric Dumazet 	bool exact = (remove == FIND);
18591da177e4SLinus Torvalds 
18604e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
18613e984840SEric Dumazet 		pkt_dev = pktgen_find_dev(t, ifname, exact);
18621da177e4SLinus Torvalds 		if (pkt_dev) {
18631da177e4SLinus Torvalds 			if (remove) {
186495ed63f7SArthur Kepner 				pkt_dev->removal_mark = 1;
186595ed63f7SArthur Kepner 				t->control |= T_REMDEV;
18661da177e4SLinus Torvalds 			}
18671da177e4SLinus Torvalds 			break;
18681da177e4SLinus Torvalds 		}
18691da177e4SLinus Torvalds 	}
18701da177e4SLinus Torvalds 	return pkt_dev;
18711da177e4SLinus Torvalds }
18721da177e4SLinus Torvalds 
187395ed63f7SArthur Kepner /*
187495ed63f7SArthur Kepner  * mark a device for removal
187595ed63f7SArthur Kepner  */
18764e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname)
18771da177e4SLinus Torvalds {
18781da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
187995ed63f7SArthur Kepner 	const int max_tries = 10, msec_per_try = 125;
188095ed63f7SArthur Kepner 	int i = 0;
188195ed63f7SArthur Kepner 
18826146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
1883f9467eaeSJoe Perches 	pr_debug("%s: marking %s for removal\n", __func__, ifname);
188495ed63f7SArthur Kepner 
188595ed63f7SArthur Kepner 	while (1) {
188695ed63f7SArthur Kepner 
18874e58a027SCong Wang 		pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE);
1888222f1806SLuiz Capitulino 		if (pkt_dev == NULL)
1889222f1806SLuiz Capitulino 			break;	/* success */
189095ed63f7SArthur Kepner 
18916146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1892f9467eaeSJoe Perches 		pr_debug("%s: waiting for %s to disappear....\n",
1893f9467eaeSJoe Perches 			 __func__, ifname);
189495ed63f7SArthur Kepner 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
18956146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
189695ed63f7SArthur Kepner 
189795ed63f7SArthur Kepner 		if (++i >= max_tries) {
1898f9467eaeSJoe Perches 			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
1899f9467eaeSJoe Perches 			       __func__, msec_per_try * i, ifname);
190095ed63f7SArthur Kepner 			break;
190195ed63f7SArthur Kepner 		}
190295ed63f7SArthur Kepner 
190395ed63f7SArthur Kepner 	}
190495ed63f7SArthur Kepner 
19056146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
190639df232fSStephen Hemminger }
190795ed63f7SArthur Kepner 
19084e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev)
190939df232fSStephen Hemminger {
191039df232fSStephen Hemminger 	struct pktgen_thread *t;
191139df232fSStephen Hemminger 
19129a0b1e8bSEric Dumazet 	mutex_lock(&pktgen_thread_lock);
19139a0b1e8bSEric Dumazet 
19144e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
191539df232fSStephen Hemminger 		struct pktgen_dev *pkt_dev;
191639df232fSStephen Hemminger 
19179a0b1e8bSEric Dumazet 		if_lock(t);
19189a0b1e8bSEric Dumazet 		list_for_each_entry(pkt_dev, &t->if_list, list) {
191939df232fSStephen Hemminger 			if (pkt_dev->odev != dev)
192039df232fSStephen Hemminger 				continue;
192139df232fSStephen Hemminger 
1922a8ca16eaSDavid Howells 			proc_remove(pkt_dev->entry);
192339df232fSStephen Hemminger 
19242975315bSAlexey Dobriyan 			pkt_dev->entry = proc_create_data(dev->name, 0600,
19254e58a027SCong Wang 							  pn->proc_dir,
192697a32539SAlexey Dobriyan 							  &pktgen_if_proc_ops,
19272975315bSAlexey Dobriyan 							  pkt_dev);
192839df232fSStephen Hemminger 			if (!pkt_dev->entry)
1929f9467eaeSJoe Perches 				pr_err("can't move proc entry for '%s'\n",
1930f9467eaeSJoe Perches 				       dev->name);
193139df232fSStephen Hemminger 			break;
193239df232fSStephen Hemminger 		}
19339a0b1e8bSEric Dumazet 		if_unlock(t);
193439df232fSStephen Hemminger 	}
19359a0b1e8bSEric Dumazet 	mutex_unlock(&pktgen_thread_lock);
19361da177e4SLinus Torvalds }
19371da177e4SLinus Torvalds 
1938222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused,
1939222f1806SLuiz Capitulino 			       unsigned long event, void *ptr)
19401da177e4SLinus Torvalds {
1941351638e7SJiri Pirko 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
19424e58a027SCong Wang 	struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id);
19431da177e4SLinus Torvalds 
19444e58a027SCong Wang 	if (pn->pktgen_exiting)
1945e9dc8653SEric W. Biederman 		return NOTIFY_DONE;
1946e9dc8653SEric W. Biederman 
19471da177e4SLinus Torvalds 	/* It is OK that we do not hold the group lock right now,
19481da177e4SLinus Torvalds 	 * as we run under the RTNL lock.
19491da177e4SLinus Torvalds 	 */
19501da177e4SLinus Torvalds 
19511da177e4SLinus Torvalds 	switch (event) {
195239df232fSStephen Hemminger 	case NETDEV_CHANGENAME:
19534e58a027SCong Wang 		pktgen_change_name(pn, dev);
19541da177e4SLinus Torvalds 		break;
19551da177e4SLinus Torvalds 
19561da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
19574e58a027SCong Wang 		pktgen_mark_device(pn, dev->name);
19581da177e4SLinus Torvalds 		break;
19593ff50b79SStephen Hemminger 	}
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	return NOTIFY_DONE;
19621da177e4SLinus Torvalds }
19631da177e4SLinus Torvalds 
19644e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn,
19654e58a027SCong Wang 						 struct pktgen_dev *pkt_dev,
196663adc6fbSStephen Hemminger 						 const char *ifname)
1967e6fce5b9SRobert Olsson {
1968e6fce5b9SRobert Olsson 	char b[IFNAMSIZ+5];
1969d6182223SPaul Gortmaker 	int i;
1970e6fce5b9SRobert Olsson 
1971e6fce5b9SRobert Olsson 	for (i = 0; ifname[i] != '@'; i++) {
1972e6fce5b9SRobert Olsson 		if (i == IFNAMSIZ)
1973e6fce5b9SRobert Olsson 			break;
1974e6fce5b9SRobert Olsson 
1975e6fce5b9SRobert Olsson 		b[i] = ifname[i];
1976e6fce5b9SRobert Olsson 	}
1977e6fce5b9SRobert Olsson 	b[i] = 0;
1978e6fce5b9SRobert Olsson 
19794e58a027SCong Wang 	return dev_get_by_name(pn->net, b);
1980e6fce5b9SRobert Olsson }
1981e6fce5b9SRobert Olsson 
1982e6fce5b9SRobert Olsson 
19831da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */
19841da177e4SLinus Torvalds 
19854e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn,
19864e58a027SCong Wang 			    struct pktgen_dev *pkt_dev, const char *ifname)
1987222f1806SLuiz Capitulino {
19881da177e4SLinus Torvalds 	struct net_device *odev;
198939df232fSStephen Hemminger 	int err;
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 	/* Clean old setups */
19921da177e4SLinus Torvalds 	if (pkt_dev->odev) {
19931da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
19941da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
19951da177e4SLinus Torvalds 	}
19961da177e4SLinus Torvalds 
19974e58a027SCong Wang 	odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname);
19981da177e4SLinus Torvalds 	if (!odev) {
1999f9467eaeSJoe Perches 		pr_err("no such netdevice: \"%s\"\n", ifname);
200039df232fSStephen Hemminger 		return -ENODEV;
20011da177e4SLinus Torvalds 	}
200239df232fSStephen Hemminger 
20031e09e581SLukas Wunner 	if (odev->type != ARPHRD_ETHER && odev->type != ARPHRD_LOOPBACK) {
20041e09e581SLukas Wunner 		pr_err("not an ethernet or loopback device: \"%s\"\n", ifname);
200539df232fSStephen Hemminger 		err = -EINVAL;
200639df232fSStephen Hemminger 	} else if (!netif_running(odev)) {
2007f9467eaeSJoe Perches 		pr_err("device is down: \"%s\"\n", ifname);
200839df232fSStephen Hemminger 		err = -ENETDOWN;
200939df232fSStephen Hemminger 	} else {
20101da177e4SLinus Torvalds 		pkt_dev->odev = odev;
201139df232fSStephen Hemminger 		return 0;
201239df232fSStephen Hemminger 	}
20131da177e4SLinus Torvalds 
20141da177e4SLinus Torvalds 	dev_put(odev);
201539df232fSStephen Hemminger 	return err;
20161da177e4SLinus Torvalds }
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev
20191da177e4SLinus Torvalds  * structure to have the right information to create/send packets
20201da177e4SLinus Torvalds  */
20211da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
20221da177e4SLinus Torvalds {
202364c00d81SAndrew Gallatin 	int ntxq;
202464c00d81SAndrew Gallatin 
20251da177e4SLinus Torvalds 	if (!pkt_dev->odev) {
2026f9467eaeSJoe Perches 		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
2027222f1806SLuiz Capitulino 		sprintf(pkt_dev->result,
2028222f1806SLuiz Capitulino 			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
20291da177e4SLinus Torvalds 		return;
20301da177e4SLinus Torvalds 	}
20311da177e4SLinus Torvalds 
203264c00d81SAndrew Gallatin 	/* make sure that we don't pick a non-existing transmit queue */
203364c00d81SAndrew Gallatin 	ntxq = pkt_dev->odev->real_num_tx_queues;
2034bfdbc0acSRobert Olsson 
203564c00d81SAndrew Gallatin 	if (ntxq <= pkt_dev->queue_map_min) {
2036294a0b7fSJoe Perches 		pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
203788271660SJesse Brandeburg 			pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
2038593f63b0SEric Dumazet 			pkt_dev->odevname);
203926e29eedSDan Carpenter 		pkt_dev->queue_map_min = (ntxq ?: 1) - 1;
204064c00d81SAndrew Gallatin 	}
204188271660SJesse Brandeburg 	if (pkt_dev->queue_map_max >= ntxq) {
2042294a0b7fSJoe Perches 		pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
204388271660SJesse Brandeburg 			pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
2044593f63b0SEric Dumazet 			pkt_dev->odevname);
204526e29eedSDan Carpenter 		pkt_dev->queue_map_max = (ntxq ?: 1) - 1;
204664c00d81SAndrew Gallatin 	}
204764c00d81SAndrew Gallatin 
20481da177e4SLinus Torvalds 	/* Default to the interface's mac if not explicitly set. */
20491da177e4SLinus Torvalds 
2050f404e9a6SKris Katterjohn 	if (is_zero_ether_addr(pkt_dev->src_mac))
20519ea08b12SJoe Perches 		ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr);
20521da177e4SLinus Torvalds 
20531da177e4SLinus Torvalds 	/* Set up Dest MAC */
20549ea08b12SJoe Perches 	ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac);
20551da177e4SLinus Torvalds 
20561da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
20574c139b8cSAmerigo Wang 		int i, set = 0, err = 1;
20584c139b8cSAmerigo Wang 		struct inet6_dev *idev;
20594c139b8cSAmerigo Wang 
206068bf9f0bSAmerigo Wang 		if (pkt_dev->min_pkt_size == 0) {
206168bf9f0bSAmerigo Wang 			pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr)
206268bf9f0bSAmerigo Wang 						+ sizeof(struct udphdr)
206368bf9f0bSAmerigo Wang 						+ sizeof(struct pktgen_hdr)
206468bf9f0bSAmerigo Wang 						+ pkt_dev->pkt_overhead;
206568bf9f0bSAmerigo Wang 		}
206668bf9f0bSAmerigo Wang 
2067df7e8e2eSEric Dumazet 		for (i = 0; i < sizeof(struct in6_addr); i++)
20681da177e4SLinus Torvalds 			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
20691da177e4SLinus Torvalds 				set = 1;
20701da177e4SLinus Torvalds 				break;
20711da177e4SLinus Torvalds 			}
20721da177e4SLinus Torvalds 
20731da177e4SLinus Torvalds 		if (!set) {
20741da177e4SLinus Torvalds 
20751da177e4SLinus Torvalds 			/*
20761da177e4SLinus Torvalds 			 * Use linklevel address if unconfigured.
20771da177e4SLinus Torvalds 			 *
20781da177e4SLinus Torvalds 			 * use ipv6_get_lladdr if/when it's get exported
20791da177e4SLinus Torvalds 			 */
20801da177e4SLinus Torvalds 
20818814c4b5SYOSHIFUJI Hideaki 			rcu_read_lock();
208263adc6fbSStephen Hemminger 			idev = __in6_dev_get(pkt_dev->odev);
208363adc6fbSStephen Hemminger 			if (idev) {
20841da177e4SLinus Torvalds 				struct inet6_ifaddr *ifp;
20851da177e4SLinus Torvalds 
20861da177e4SLinus Torvalds 				read_lock_bh(&idev->lock);
20874c139b8cSAmerigo Wang 				list_for_each_entry(ifp, &idev->addr_list, if_list) {
20884c139b8cSAmerigo Wang 					if ((ifp->scope & IFA_LINK) &&
2089f64f9e71SJoe Perches 					    !(ifp->flags & IFA_F_TENTATIVE)) {
20904e3fd7a0SAlexey Dobriyan 						pkt_dev->cur_in6_saddr = ifp->addr;
20911da177e4SLinus Torvalds 						err = 0;
20921da177e4SLinus Torvalds 						break;
20931da177e4SLinus Torvalds 					}
20941da177e4SLinus Torvalds 				}
20951da177e4SLinus Torvalds 				read_unlock_bh(&idev->lock);
20961da177e4SLinus Torvalds 			}
20978814c4b5SYOSHIFUJI Hideaki 			rcu_read_unlock();
2098222f1806SLuiz Capitulino 			if (err)
2099f9467eaeSJoe Perches 				pr_err("ERROR: IPv6 link address not available\n");
21001da177e4SLinus Torvalds 		}
2101222f1806SLuiz Capitulino 	} else {
210268bf9f0bSAmerigo Wang 		if (pkt_dev->min_pkt_size == 0) {
210368bf9f0bSAmerigo Wang 			pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr)
210468bf9f0bSAmerigo Wang 						+ sizeof(struct udphdr)
210568bf9f0bSAmerigo Wang 						+ sizeof(struct pktgen_hdr)
210668bf9f0bSAmerigo Wang 						+ pkt_dev->pkt_overhead;
210768bf9f0bSAmerigo Wang 		}
210868bf9f0bSAmerigo Wang 
21091da177e4SLinus Torvalds 		pkt_dev->saddr_min = 0;
21101da177e4SLinus Torvalds 		pkt_dev->saddr_max = 0;
21111da177e4SLinus Torvalds 		if (strlen(pkt_dev->src_min) == 0) {
21121da177e4SLinus Torvalds 
21131da177e4SLinus Torvalds 			struct in_device *in_dev;
21141da177e4SLinus Torvalds 
21151da177e4SLinus Torvalds 			rcu_read_lock();
2116e5ed6399SHerbert Xu 			in_dev = __in_dev_get_rcu(pkt_dev->odev);
21171da177e4SLinus Torvalds 			if (in_dev) {
21182638eb8bSFlorian Westphal 				const struct in_ifaddr *ifa;
21192638eb8bSFlorian Westphal 
21202638eb8bSFlorian Westphal 				ifa = rcu_dereference(in_dev->ifa_list);
21212638eb8bSFlorian Westphal 				if (ifa) {
21222638eb8bSFlorian Westphal 					pkt_dev->saddr_min = ifa->ifa_address;
21231da177e4SLinus Torvalds 					pkt_dev->saddr_max = pkt_dev->saddr_min;
21241da177e4SLinus Torvalds 				}
21251da177e4SLinus Torvalds 			}
21261da177e4SLinus Torvalds 			rcu_read_unlock();
2127222f1806SLuiz Capitulino 		} else {
21281da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
21291da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
21301da177e4SLinus Torvalds 		}
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds 		pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
21331da177e4SLinus Torvalds 		pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
21341da177e4SLinus Torvalds 	}
21351da177e4SLinus Torvalds 	/* Initialize current values. */
213668bf9f0bSAmerigo Wang 	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
213768bf9f0bSAmerigo Wang 	if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size)
213868bf9f0bSAmerigo Wang 		pkt_dev->max_pkt_size = pkt_dev->min_pkt_size;
213968bf9f0bSAmerigo Wang 
21401da177e4SLinus Torvalds 	pkt_dev->cur_dst_mac_offset = 0;
21411da177e4SLinus Torvalds 	pkt_dev->cur_src_mac_offset = 0;
21421da177e4SLinus Torvalds 	pkt_dev->cur_saddr = pkt_dev->saddr_min;
21431da177e4SLinus Torvalds 	pkt_dev->cur_daddr = pkt_dev->daddr_min;
21441da177e4SLinus Torvalds 	pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
21451da177e4SLinus Torvalds 	pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
21461da177e4SLinus Torvalds 	pkt_dev->nflows = 0;
21471da177e4SLinus Torvalds }
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds 
2150fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
2151fd29cf72SStephen Hemminger {
2152ef87979cSStephen Hemminger 	ktime_t start_time, end_time;
2153417bc4b8SEric Dumazet 	s64 remaining;
21542bc481cfSStephen Hemminger 	struct hrtimer_sleeper t;
2155fd29cf72SStephen Hemminger 
2156dbc1625fSSebastian Andrzej Siewior 	hrtimer_init_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
21572bc481cfSStephen Hemminger 	hrtimer_set_expires(&t.timer, spin_until);
2158fd29cf72SStephen Hemminger 
215943d28b65SDaniel Turull 	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
2160bcf91bdbSGuenter Roeck 	if (remaining <= 0)
2161bcf91bdbSGuenter Roeck 		goto out;
21622bc481cfSStephen Hemminger 
2163398f382cSDaniel Borkmann 	start_time = ktime_get();
216433136d12SEric Dumazet 	if (remaining < 100000) {
216533136d12SEric Dumazet 		/* for small delays (<100us), just loop until limit is reached */
216633136d12SEric Dumazet 		do {
2167398f382cSDaniel Borkmann 			end_time = ktime_get();
2168398f382cSDaniel Borkmann 		} while (ktime_compare(end_time, spin_until) < 0);
216933136d12SEric Dumazet 	} else {
21702bc481cfSStephen Hemminger 		do {
21712bc481cfSStephen Hemminger 			set_current_state(TASK_INTERRUPTIBLE);
21729dd8813eSThomas Gleixner 			hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_ABS);
21732bc481cfSStephen Hemminger 
21742bc481cfSStephen Hemminger 			if (likely(t.task))
21751da177e4SLinus Torvalds 				schedule();
21761da177e4SLinus Torvalds 
21772bc481cfSStephen Hemminger 			hrtimer_cancel(&t.timer);
21782bc481cfSStephen Hemminger 		} while (t.task && pkt_dev->running && !signal_pending(current));
21792bc481cfSStephen Hemminger 		__set_current_state(TASK_RUNNING);
2180398f382cSDaniel Borkmann 		end_time = ktime_get();
218133136d12SEric Dumazet 	}
2182ef87979cSStephen Hemminger 
2183ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
2184bcf91bdbSGuenter Roeck out:
218507a0f0f0SDaniel Turull 	pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
2186bcf91bdbSGuenter Roeck 	destroy_hrtimer_on_stack(&t.timer);
21871da177e4SLinus Torvalds }
21881da177e4SLinus Torvalds 
218916dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
219016dab72fSJamal Hadi Salim {
219163d75463SPaolo Abeni 	pkt_dev->pkt_overhead = 0;
219216dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
219316dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
219416dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
219516dab72fSJamal Hadi Salim }
219616dab72fSJamal Hadi Salim 
2197648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
2198007a531bSJamal Hadi Salim {
2199648fda74SStephen Hemminger 	return !!(pkt_dev->flows[flow].flags & F_INIT);
2200007a531bSJamal Hadi Salim }
2201007a531bSJamal Hadi Salim 
2202007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev)
2203007a531bSJamal Hadi Salim {
2204007a531bSJamal Hadi Salim 	int flow = pkt_dev->curfl;
2205007a531bSJamal Hadi Salim 
2206007a531bSJamal Hadi Salim 	if (pkt_dev->flags & F_FLOW_SEQ) {
2207007a531bSJamal Hadi Salim 		if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
2208007a531bSJamal Hadi Salim 			/* reset time */
2209007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
22101211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
2211007a531bSJamal Hadi Salim 			pkt_dev->curfl += 1;
2212007a531bSJamal Hadi Salim 			if (pkt_dev->curfl >= pkt_dev->cflows)
2213007a531bSJamal Hadi Salim 				pkt_dev->curfl = 0; /*reset */
2214007a531bSJamal Hadi Salim 		}
2215007a531bSJamal Hadi Salim 	} else {
221633d7c5e5SAkinobu Mita 		flow = prandom_u32() % pkt_dev->cflows;
22171211a645SRobert Olsson 		pkt_dev->curfl = flow;
2218007a531bSJamal Hadi Salim 
22191211a645SRobert Olsson 		if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
2220007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
22211211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
22221211a645SRobert Olsson 		}
2223007a531bSJamal Hadi Salim 	}
2224007a531bSJamal Hadi Salim 
2225007a531bSJamal Hadi Salim 	return pkt_dev->curfl;
2226007a531bSJamal Hadi Salim }
2227007a531bSJamal Hadi Salim 
2228a553e4a6SJamal Hadi Salim 
2229a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2230a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else
2231a553e4a6SJamal Hadi Salim  * we go look for it ...
2232a553e4a6SJamal Hadi Salim */
2233bd55775cSJamal Hadi Salim #define DUMMY_MARK 0
2234fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
2235a553e4a6SJamal Hadi Salim {
2236a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[flow].x;
22374e58a027SCong Wang 	struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
2238a553e4a6SJamal Hadi Salim 	if (!x) {
2239c454997eSFan Du 
2240c454997eSFan Du 		if (pkt_dev->spi) {
2241c454997eSFan Du 			/* We need as quick as possible to find the right SA
2242c454997eSFan Du 			 * Searching with minimum criteria to archieve this.
2243c454997eSFan Du 			 */
2244c454997eSFan Du 			x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
2245c454997eSFan Du 		} else {
2246a553e4a6SJamal Hadi Salim 			/* slow path: we dont already have xfrm_state */
22477e652640SSteffen Klassert 			x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0,
22485447c5e4SAlexey Dobriyan 						(xfrm_address_t *)&pkt_dev->cur_daddr,
2249a553e4a6SJamal Hadi Salim 						(xfrm_address_t *)&pkt_dev->cur_saddr,
2250a553e4a6SJamal Hadi Salim 						AF_INET,
2251a553e4a6SJamal Hadi Salim 						pkt_dev->ipsmode,
2252a553e4a6SJamal Hadi Salim 						pkt_dev->ipsproto, 0);
2253c454997eSFan Du 		}
2254a553e4a6SJamal Hadi Salim 		if (x) {
2255a553e4a6SJamal Hadi Salim 			pkt_dev->flows[flow].x = x;
2256a553e4a6SJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
2257a553e4a6SJamal Hadi Salim 			pkt_dev->pkt_overhead += x->props.header_len;
2258a553e4a6SJamal Hadi Salim 		}
2259a553e4a6SJamal Hadi Salim 
2260a553e4a6SJamal Hadi Salim 	}
2261a553e4a6SJamal Hadi Salim }
2262a553e4a6SJamal Hadi Salim #endif
2263fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
2264fd2ea0a7SDavid S. Miller {
2265e6fce5b9SRobert Olsson 
2266e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
2267e6fce5b9SRobert Olsson 		pkt_dev->cur_queue_map = smp_processor_id();
2268e6fce5b9SRobert Olsson 
2269896a7cf8SEric Dumazet 	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
2270fd2ea0a7SDavid S. Miller 		__u16 t;
2271fd2ea0a7SDavid S. Miller 		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
227233d7c5e5SAkinobu Mita 			t = prandom_u32() %
2273fd2ea0a7SDavid S. Miller 				(pkt_dev->queue_map_max -
2274fd2ea0a7SDavid S. Miller 				 pkt_dev->queue_map_min + 1)
2275fd2ea0a7SDavid S. Miller 				+ pkt_dev->queue_map_min;
2276fd2ea0a7SDavid S. Miller 		} else {
2277fd2ea0a7SDavid S. Miller 			t = pkt_dev->cur_queue_map + 1;
2278fd2ea0a7SDavid S. Miller 			if (t > pkt_dev->queue_map_max)
2279fd2ea0a7SDavid S. Miller 				t = pkt_dev->queue_map_min;
2280fd2ea0a7SDavid S. Miller 		}
2281fd2ea0a7SDavid S. Miller 		pkt_dev->cur_queue_map = t;
2282fd2ea0a7SDavid S. Miller 	}
2283bfdbc0acSRobert Olsson 	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
2284fd2ea0a7SDavid S. Miller }
2285fd2ea0a7SDavid S. Miller 
22861da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values
22871da177e4SLinus Torvalds  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
22881da177e4SLinus Torvalds  */
2289222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev)
2290222f1806SLuiz Capitulino {
22911da177e4SLinus Torvalds 	__u32 imn;
22921da177e4SLinus Torvalds 	__u32 imx;
22931da177e4SLinus Torvalds 	int flow = 0;
22941da177e4SLinus Torvalds 
2295007a531bSJamal Hadi Salim 	if (pkt_dev->cflows)
2296007a531bSJamal Hadi Salim 		flow = f_pick(pkt_dev);
22971da177e4SLinus Torvalds 
22981da177e4SLinus Torvalds 	/*  Deal with source MAC */
22991da177e4SLinus Torvalds 	if (pkt_dev->src_mac_count > 1) {
23001da177e4SLinus Torvalds 		__u32 mc;
23011da177e4SLinus Torvalds 		__u32 tmp;
23021da177e4SLinus Torvalds 
23031da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACSRC_RND)
230433d7c5e5SAkinobu Mita 			mc = prandom_u32() % pkt_dev->src_mac_count;
23051da177e4SLinus Torvalds 		else {
23061da177e4SLinus Torvalds 			mc = pkt_dev->cur_src_mac_offset++;
2307ff2a79a5SRobert Olsson 			if (pkt_dev->cur_src_mac_offset >=
2308222f1806SLuiz Capitulino 			    pkt_dev->src_mac_count)
23091da177e4SLinus Torvalds 				pkt_dev->cur_src_mac_offset = 0;
23101da177e4SLinus Torvalds 		}
23111da177e4SLinus Torvalds 
23121da177e4SLinus Torvalds 		tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
23131da177e4SLinus Torvalds 		pkt_dev->hh[11] = tmp;
23141da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
23151da177e4SLinus Torvalds 		pkt_dev->hh[10] = tmp;
23161da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
23171da177e4SLinus Torvalds 		pkt_dev->hh[9] = tmp;
23181da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
23191da177e4SLinus Torvalds 		pkt_dev->hh[8] = tmp;
23201da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
23211da177e4SLinus Torvalds 		pkt_dev->hh[7] = tmp;
23221da177e4SLinus Torvalds 	}
23231da177e4SLinus Torvalds 
23241da177e4SLinus Torvalds 	/*  Deal with Destination MAC */
23251da177e4SLinus Torvalds 	if (pkt_dev->dst_mac_count > 1) {
23261da177e4SLinus Torvalds 		__u32 mc;
23271da177e4SLinus Torvalds 		__u32 tmp;
23281da177e4SLinus Torvalds 
23291da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACDST_RND)
233033d7c5e5SAkinobu Mita 			mc = prandom_u32() % pkt_dev->dst_mac_count;
23311da177e4SLinus Torvalds 
23321da177e4SLinus Torvalds 		else {
23331da177e4SLinus Torvalds 			mc = pkt_dev->cur_dst_mac_offset++;
2334ff2a79a5SRobert Olsson 			if (pkt_dev->cur_dst_mac_offset >=
2335222f1806SLuiz Capitulino 			    pkt_dev->dst_mac_count) {
23361da177e4SLinus Torvalds 				pkt_dev->cur_dst_mac_offset = 0;
23371da177e4SLinus Torvalds 			}
23381da177e4SLinus Torvalds 		}
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds 		tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
23411da177e4SLinus Torvalds 		pkt_dev->hh[5] = tmp;
23421da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
23431da177e4SLinus Torvalds 		pkt_dev->hh[4] = tmp;
23441da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
23451da177e4SLinus Torvalds 		pkt_dev->hh[3] = tmp;
23461da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
23471da177e4SLinus Torvalds 		pkt_dev->hh[2] = tmp;
23481da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
23491da177e4SLinus Torvalds 		pkt_dev->hh[1] = tmp;
23501da177e4SLinus Torvalds 	}
23511da177e4SLinus Torvalds 
2352ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND) {
235395c96174SEric Dumazet 		unsigned int i;
2354ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
2355ca6549afSSteven Whitehouse 			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
2356ca6549afSSteven Whitehouse 				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
235733d7c5e5SAkinobu Mita 					     ((__force __be32)prandom_u32() &
2358ca6549afSSteven Whitehouse 						      htonl(0x000fffff));
2359ca6549afSSteven Whitehouse 	}
2360ca6549afSSteven Whitehouse 
236134954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
236233d7c5e5SAkinobu Mita 		pkt_dev->vlan_id = prandom_u32() & (4096 - 1);
236334954ddcSFrancesco Fondelli 	}
236434954ddcSFrancesco Fondelli 
236534954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
236633d7c5e5SAkinobu Mita 		pkt_dev->svlan_id = prandom_u32() & (4096 - 1);
236734954ddcSFrancesco Fondelli 	}
236834954ddcSFrancesco Fondelli 
23691da177e4SLinus Torvalds 	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
23701da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPSRC_RND)
237133d7c5e5SAkinobu Mita 			pkt_dev->cur_udp_src = prandom_u32() %
23725fa6fc76SStephen Hemminger 				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
23735fa6fc76SStephen Hemminger 				+ pkt_dev->udp_src_min;
23741da177e4SLinus Torvalds 
23751da177e4SLinus Torvalds 		else {
23761da177e4SLinus Torvalds 			pkt_dev->cur_udp_src++;
23771da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
23781da177e4SLinus Torvalds 				pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
23791da177e4SLinus Torvalds 		}
23801da177e4SLinus Torvalds 	}
23811da177e4SLinus Torvalds 
23821da177e4SLinus Torvalds 	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
23831da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPDST_RND) {
238433d7c5e5SAkinobu Mita 			pkt_dev->cur_udp_dst = prandom_u32() %
23855fa6fc76SStephen Hemminger 				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
23865fa6fc76SStephen Hemminger 				+ pkt_dev->udp_dst_min;
2387222f1806SLuiz Capitulino 		} else {
23881da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst++;
23891da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
23901da177e4SLinus Torvalds 				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
23911da177e4SLinus Torvalds 		}
23921da177e4SLinus Torvalds 	}
23931da177e4SLinus Torvalds 
23941da177e4SLinus Torvalds 	if (!(pkt_dev->flags & F_IPV6)) {
23951da177e4SLinus Torvalds 
239663adc6fbSStephen Hemminger 		imn = ntohl(pkt_dev->saddr_min);
239763adc6fbSStephen Hemminger 		imx = ntohl(pkt_dev->saddr_max);
239863adc6fbSStephen Hemminger 		if (imn < imx) {
23991da177e4SLinus Torvalds 			__u32 t;
24001da177e4SLinus Torvalds 			if (pkt_dev->flags & F_IPSRC_RND)
240133d7c5e5SAkinobu Mita 				t = prandom_u32() % (imx - imn) + imn;
24021da177e4SLinus Torvalds 			else {
24031da177e4SLinus Torvalds 				t = ntohl(pkt_dev->cur_saddr);
24041da177e4SLinus Torvalds 				t++;
240563adc6fbSStephen Hemminger 				if (t > imx)
24061da177e4SLinus Torvalds 					t = imn;
240763adc6fbSStephen Hemminger 
24081da177e4SLinus Torvalds 			}
24091da177e4SLinus Torvalds 			pkt_dev->cur_saddr = htonl(t);
24101da177e4SLinus Torvalds 		}
24111da177e4SLinus Torvalds 
2412007a531bSJamal Hadi Salim 		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
24131da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
24141da177e4SLinus Torvalds 		} else {
2415252e3346SAl Viro 			imn = ntohl(pkt_dev->daddr_min);
2416252e3346SAl Viro 			imx = ntohl(pkt_dev->daddr_max);
2417252e3346SAl Viro 			if (imn < imx) {
24181da177e4SLinus Torvalds 				__u32 t;
2419252e3346SAl Viro 				__be32 s;
24201da177e4SLinus Torvalds 				if (pkt_dev->flags & F_IPDST_RND) {
24211da177e4SLinus Torvalds 
242270e3ba72SAkinobu Mita 					do {
242333d7c5e5SAkinobu Mita 						t = prandom_u32() %
242433d7c5e5SAkinobu Mita 							(imx - imn) + imn;
2425252e3346SAl Viro 						s = htonl(t);
242670e3ba72SAkinobu Mita 					} while (ipv4_is_loopback(s) ||
242770e3ba72SAkinobu Mita 						ipv4_is_multicast(s) ||
242870e3ba72SAkinobu Mita 						ipv4_is_lbcast(s) ||
242970e3ba72SAkinobu Mita 						ipv4_is_zeronet(s) ||
243070e3ba72SAkinobu Mita 						ipv4_is_local_multicast(s));
2431252e3346SAl Viro 					pkt_dev->cur_daddr = s;
2432252e3346SAl Viro 				} else {
24331da177e4SLinus Torvalds 					t = ntohl(pkt_dev->cur_daddr);
24341da177e4SLinus Torvalds 					t++;
24351da177e4SLinus Torvalds 					if (t > imx) {
24361da177e4SLinus Torvalds 						t = imn;
24371da177e4SLinus Torvalds 					}
24381da177e4SLinus Torvalds 					pkt_dev->cur_daddr = htonl(t);
24391da177e4SLinus Torvalds 				}
24401da177e4SLinus Torvalds 			}
24411da177e4SLinus Torvalds 			if (pkt_dev->cflows) {
2442007a531bSJamal Hadi Salim 				pkt_dev->flows[flow].flags |= F_INIT;
2443222f1806SLuiz Capitulino 				pkt_dev->flows[flow].cur_daddr =
2444222f1806SLuiz Capitulino 				    pkt_dev->cur_daddr;
2445a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
24466f107c74SDmitry Safonov 				if (pkt_dev->flags & F_IPSEC)
2447a553e4a6SJamal Hadi Salim 					get_ipsec_sa(pkt_dev, flow);
2448a553e4a6SJamal Hadi Salim #endif
24491da177e4SLinus Torvalds 				pkt_dev->nflows++;
24501da177e4SLinus Torvalds 			}
24511da177e4SLinus Torvalds 		}
2452222f1806SLuiz Capitulino 	} else {		/* IPV6 * */
2453222f1806SLuiz Capitulino 
245406e30411SJoe Perches 		if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) {
24551da177e4SLinus Torvalds 			int i;
24561da177e4SLinus Torvalds 
24571da177e4SLinus Torvalds 			/* Only random destinations yet */
24581da177e4SLinus Torvalds 
24591da177e4SLinus Torvalds 			for (i = 0; i < 4; i++) {
24601da177e4SLinus Torvalds 				pkt_dev->cur_in6_daddr.s6_addr32[i] =
246133d7c5e5SAkinobu Mita 				    (((__force __be32)prandom_u32() |
24621da177e4SLinus Torvalds 				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
24631da177e4SLinus Torvalds 				     pkt_dev->max_in6_daddr.s6_addr32[i]);
24641da177e4SLinus Torvalds 			}
24651da177e4SLinus Torvalds 		}
24661da177e4SLinus Torvalds 	}
24671da177e4SLinus Torvalds 
24681da177e4SLinus Torvalds 	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
24691da177e4SLinus Torvalds 		__u32 t;
24701da177e4SLinus Torvalds 		if (pkt_dev->flags & F_TXSIZE_RND) {
247133d7c5e5SAkinobu Mita 			t = prandom_u32() %
24725fa6fc76SStephen Hemminger 				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
24735fa6fc76SStephen Hemminger 				+ pkt_dev->min_pkt_size;
2474222f1806SLuiz Capitulino 		} else {
24751da177e4SLinus Torvalds 			t = pkt_dev->cur_pkt_size + 1;
24761da177e4SLinus Torvalds 			if (t > pkt_dev->max_pkt_size)
24771da177e4SLinus Torvalds 				t = pkt_dev->min_pkt_size;
24781da177e4SLinus Torvalds 		}
24791da177e4SLinus Torvalds 		pkt_dev->cur_pkt_size = t;
24801da177e4SLinus Torvalds 	}
24811da177e4SLinus Torvalds 
2482fd2ea0a7SDavid S. Miller 	set_cur_queue_map(pkt_dev);
248345b270f8SRobert Olsson 
24841da177e4SLinus Torvalds 	pkt_dev->flows[flow].count++;
24851da177e4SLinus Torvalds }
24861da177e4SLinus Torvalds 
2487a553e4a6SJamal Hadi Salim 
2488a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
24895537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
2490cf93d47eSFan Du 
2491cf93d47eSFan Du 	[RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
2492cf93d47eSFan Du };
2493cf93d47eSFan Du 
2494a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
2495a553e4a6SJamal Hadi Salim {
2496a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2497a553e4a6SJamal Hadi Salim 	int err = 0;
24986de9ace4SFan Du 	struct net *net = dev_net(pkt_dev->odev);
2499a553e4a6SJamal Hadi Salim 
2500a553e4a6SJamal Hadi Salim 	if (!x)
2501a553e4a6SJamal Hadi Salim 		return 0;
2502a553e4a6SJamal Hadi Salim 	/* XXX: we dont support tunnel mode for now until
2503a553e4a6SJamal Hadi Salim 	 * we resolve the dst issue */
2504cf93d47eSFan Du 	if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
2505a553e4a6SJamal Hadi Salim 		return 0;
2506a553e4a6SJamal Hadi Salim 
2507cf93d47eSFan Du 	/* But when user specify an valid SPI, transformation
2508cf93d47eSFan Du 	 * supports both transport/tunnel mode + ESP/AH type.
2509cf93d47eSFan Du 	 */
2510cf93d47eSFan Du 	if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
2511b6ca8bd5SDavid Miller 		skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF;
2512cf93d47eSFan Du 
2513cf93d47eSFan Du 	rcu_read_lock_bh();
25140c620e97SFlorian Westphal 	err = pktgen_xfrm_outer_mode_output(x, skb);
2515cf93d47eSFan Du 	rcu_read_unlock_bh();
25166de9ace4SFan Du 	if (err) {
25176de9ace4SFan Du 		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
2518a553e4a6SJamal Hadi Salim 		goto error;
25196de9ace4SFan Du 	}
2520a553e4a6SJamal Hadi Salim 	err = x->type->output(x, skb);
25216de9ace4SFan Du 	if (err) {
25226de9ace4SFan Du 		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
2523a553e4a6SJamal Hadi Salim 		goto error;
25246de9ace4SFan Du 	}
25250af0a413SFan Du 	spin_lock_bh(&x->lock);
2526a553e4a6SJamal Hadi Salim 	x->curlft.bytes += skb->len;
2527a553e4a6SJamal Hadi Salim 	x->curlft.packets++;
25280af0a413SFan Du 	spin_unlock_bh(&x->lock);
2529a553e4a6SJamal Hadi Salim error:
2530a553e4a6SJamal Hadi Salim 	return err;
2531a553e4a6SJamal Hadi Salim }
2532a553e4a6SJamal Hadi Salim 
2533475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev)
2534a553e4a6SJamal Hadi Salim {
2535a553e4a6SJamal Hadi Salim 	if (pkt_dev->cflows) {
2536a553e4a6SJamal Hadi Salim 		/* let go of the SAs if we have them */
2537d6182223SPaul Gortmaker 		int i;
2538d6182223SPaul Gortmaker 		for (i = 0; i < pkt_dev->cflows; i++) {
2539a553e4a6SJamal Hadi Salim 			struct xfrm_state *x = pkt_dev->flows[i].x;
2540a553e4a6SJamal Hadi Salim 			if (x) {
2541a553e4a6SJamal Hadi Salim 				xfrm_state_put(x);
2542a553e4a6SJamal Hadi Salim 				pkt_dev->flows[i].x = NULL;
2543a553e4a6SJamal Hadi Salim 			}
2544a553e4a6SJamal Hadi Salim 		}
2545a553e4a6SJamal Hadi Salim 	}
2546a553e4a6SJamal Hadi Salim }
2547a553e4a6SJamal Hadi Salim 
2548475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev,
2549a553e4a6SJamal Hadi Salim 			      struct sk_buff *skb, __be16 protocol)
2550a553e4a6SJamal Hadi Salim {
25516f107c74SDmitry Safonov 	if (pkt_dev->flags & F_IPSEC) {
2552a553e4a6SJamal Hadi Salim 		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2553a553e4a6SJamal Hadi Salim 		int nhead = 0;
2554a553e4a6SJamal Hadi Salim 		if (x) {
2555d4969581SEric Dumazet 			struct ethhdr *eth;
25563868204dSfan.du 			struct iphdr *iph;
2557d4969581SEric Dumazet 			int ret;
25583868204dSfan.du 
2559a553e4a6SJamal Hadi Salim 			nhead = x->props.header_len - skb_headroom(skb);
2560a553e4a6SJamal Hadi Salim 			if (nhead > 0) {
2561a553e4a6SJamal Hadi Salim 				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
2562a553e4a6SJamal Hadi Salim 				if (ret < 0) {
2563f9467eaeSJoe Perches 					pr_err("Error expanding ipsec packet %d\n",
2564f9467eaeSJoe Perches 					       ret);
2565b4bb4ac8SIlpo Järvinen 					goto err;
2566a553e4a6SJamal Hadi Salim 				}
2567a553e4a6SJamal Hadi Salim 			}
2568a553e4a6SJamal Hadi Salim 
2569a553e4a6SJamal Hadi Salim 			/* ipsec is not expecting ll header */
2570a553e4a6SJamal Hadi Salim 			skb_pull(skb, ETH_HLEN);
2571a553e4a6SJamal Hadi Salim 			ret = pktgen_output_ipsec(skb, pkt_dev);
2572a553e4a6SJamal Hadi Salim 			if (ret) {
2573f9467eaeSJoe Perches 				pr_err("Error creating ipsec packet %d\n", ret);
2574b4bb4ac8SIlpo Järvinen 				goto err;
2575a553e4a6SJamal Hadi Salim 			}
2576a553e4a6SJamal Hadi Salim 			/* restore ll */
2577d58ff351SJohannes Berg 			eth = skb_push(skb, ETH_HLEN);
2578d4969581SEric Dumazet 			memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN);
2579d4969581SEric Dumazet 			eth->h_proto = protocol;
25803868204dSfan.du 
25813868204dSfan.du 			/* Update IPv4 header len as well as checksum value */
25823868204dSfan.du 			iph = ip_hdr(skb);
25833868204dSfan.du 			iph->tot_len = htons(skb->len - ETH_HLEN);
25843868204dSfan.du 			ip_send_check(iph);
2585a553e4a6SJamal Hadi Salim 		}
2586a553e4a6SJamal Hadi Salim 	}
2587a553e4a6SJamal Hadi Salim 	return 1;
2588b4bb4ac8SIlpo Järvinen err:
2589b4bb4ac8SIlpo Järvinen 	kfree_skb(skb);
2590b4bb4ac8SIlpo Järvinen 	return 0;
2591a553e4a6SJamal Hadi Salim }
2592a553e4a6SJamal Hadi Salim #endif
2593a553e4a6SJamal Hadi Salim 
2594ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
2595ca6549afSSteven Whitehouse {
259695c96174SEric Dumazet 	unsigned int i;
259763adc6fbSStephen Hemminger 	for (i = 0; i < pkt_dev->nr_labels; i++)
2598ca6549afSSteven Whitehouse 		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
259963adc6fbSStephen Hemminger 
2600ca6549afSSteven Whitehouse 	mpls--;
2601ca6549afSSteven Whitehouse 	*mpls |= MPLS_STACK_BOTTOM;
2602ca6549afSSteven Whitehouse }
2603ca6549afSSteven Whitehouse 
26040f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi,
26050f37c605SAl Viro 			       unsigned int prio)
26060f37c605SAl Viro {
26070f37c605SAl Viro 	return htons(id | (cfi << 12) | (prio << 13));
26080f37c605SAl Viro }
26090f37c605SAl Viro 
261026ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
261126ad7879SEric Dumazet 				int datalen)
261226ad7879SEric Dumazet {
26137f5d3f27SArnd Bergmann 	struct timespec64 timestamp;
261426ad7879SEric Dumazet 	struct pktgen_hdr *pgh;
261526ad7879SEric Dumazet 
26164df864c1SJohannes Berg 	pgh = skb_put(skb, sizeof(*pgh));
261726ad7879SEric Dumazet 	datalen -= sizeof(*pgh);
261826ad7879SEric Dumazet 
261926ad7879SEric Dumazet 	if (pkt_dev->nfrags <= 0) {
2620b080db58SJohannes Berg 		skb_put_zero(skb, datalen);
262126ad7879SEric Dumazet 	} else {
262226ad7879SEric Dumazet 		int frags = pkt_dev->nfrags;
262326ad7879SEric Dumazet 		int i, len;
26247d36a991Samit salecha 		int frag_len;
262526ad7879SEric Dumazet 
262626ad7879SEric Dumazet 
262726ad7879SEric Dumazet 		if (frags > MAX_SKB_FRAGS)
262826ad7879SEric Dumazet 			frags = MAX_SKB_FRAGS;
262926ad7879SEric Dumazet 		len = datalen - frags * PAGE_SIZE;
263026ad7879SEric Dumazet 		if (len > 0) {
2631b080db58SJohannes Berg 			skb_put_zero(skb, len);
263226ad7879SEric Dumazet 			datalen = frags * PAGE_SIZE;
263326ad7879SEric Dumazet 		}
263426ad7879SEric Dumazet 
263526ad7879SEric Dumazet 		i = 0;
26367d36a991Samit salecha 		frag_len = (datalen/frags) < PAGE_SIZE ?
26377d36a991Samit salecha 			   (datalen/frags) : PAGE_SIZE;
263826ad7879SEric Dumazet 		while (datalen > 0) {
263926ad7879SEric Dumazet 			if (unlikely(!pkt_dev->page)) {
264026ad7879SEric Dumazet 				int node = numa_node_id();
264126ad7879SEric Dumazet 
264226ad7879SEric Dumazet 				if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
264326ad7879SEric Dumazet 					node = pkt_dev->node;
264426ad7879SEric Dumazet 				pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
264526ad7879SEric Dumazet 				if (!pkt_dev->page)
264626ad7879SEric Dumazet 					break;
264726ad7879SEric Dumazet 			}
2648a0bec1cdSIan Campbell 			get_page(pkt_dev->page);
2649ea2ab693SIan Campbell 			skb_frag_set_page(skb, i, pkt_dev->page);
2650b54c9d5bSJonathan Lemon 			skb_frag_off_set(&skb_shinfo(skb)->frags[i], 0);
26517d36a991Samit salecha 			/*last fragment, fill rest of data*/
26527d36a991Samit salecha 			if (i == (frags - 1))
26539e903e08SEric Dumazet 				skb_frag_size_set(&skb_shinfo(skb)->frags[i],
26549e903e08SEric Dumazet 				    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE));
26557d36a991Samit salecha 			else
26569e903e08SEric Dumazet 				skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len);
26579e903e08SEric Dumazet 			datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
26589e903e08SEric Dumazet 			skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
26599e903e08SEric Dumazet 			skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
266026ad7879SEric Dumazet 			i++;
266126ad7879SEric Dumazet 			skb_shinfo(skb)->nr_frags = i;
266226ad7879SEric Dumazet 		}
266326ad7879SEric Dumazet 	}
266426ad7879SEric Dumazet 
266526ad7879SEric Dumazet 	/* Stamp the time, and sequence number,
266626ad7879SEric Dumazet 	 * convert them to network byte order
266726ad7879SEric Dumazet 	 */
266826ad7879SEric Dumazet 	pgh->pgh_magic = htonl(PKTGEN_MAGIC);
266926ad7879SEric Dumazet 	pgh->seq_num = htonl(pkt_dev->seq_num);
267026ad7879SEric Dumazet 
2671afb84b62SJesper Dangaard Brouer 	if (pkt_dev->flags & F_NO_TIMESTAMP) {
2672afb84b62SJesper Dangaard Brouer 		pgh->tv_sec = 0;
2673afb84b62SJesper Dangaard Brouer 		pgh->tv_usec = 0;
2674afb84b62SJesper Dangaard Brouer 	} else {
26757f5d3f27SArnd Bergmann 		/*
26767f5d3f27SArnd Bergmann 		 * pgh->tv_sec wraps in y2106 when interpreted as unsigned
26777f5d3f27SArnd Bergmann 		 * as done by wireshark, or y2038 when interpreted as signed.
26787f5d3f27SArnd Bergmann 		 * This is probably harmless, but if anyone wants to improve
26797f5d3f27SArnd Bergmann 		 * it, we could introduce a variant that puts 64-bit nanoseconds
26807f5d3f27SArnd Bergmann 		 * into the respective header bytes.
26817f5d3f27SArnd Bergmann 		 * This would also be slightly faster to read.
26827f5d3f27SArnd Bergmann 		 */
26837f5d3f27SArnd Bergmann 		ktime_get_real_ts64(&timestamp);
268426ad7879SEric Dumazet 		pgh->tv_sec = htonl(timestamp.tv_sec);
26857f5d3f27SArnd Bergmann 		pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC);
268626ad7879SEric Dumazet 	}
2687afb84b62SJesper Dangaard Brouer }
268826ad7879SEric Dumazet 
26897a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
269063d75463SPaolo Abeni 					struct pktgen_dev *pkt_dev)
26917a6e288dSDaniel Borkmann {
269263d75463SPaolo Abeni 	unsigned int extralen = LL_RESERVED_SPACE(dev);
26937a6e288dSDaniel Borkmann 	struct sk_buff *skb = NULL;
269463d75463SPaolo Abeni 	unsigned int size;
26957a6e288dSDaniel Borkmann 
269663d75463SPaolo Abeni 	size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead;
26977a6e288dSDaniel Borkmann 	if (pkt_dev->flags & F_NODE) {
26987a6e288dSDaniel Borkmann 		int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();
26997a6e288dSDaniel Borkmann 
27007a6e288dSDaniel Borkmann 		skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node);
27017a6e288dSDaniel Borkmann 		if (likely(skb)) {
27027a6e288dSDaniel Borkmann 			skb_reserve(skb, NET_SKB_PAD);
27037a6e288dSDaniel Borkmann 			skb->dev = dev;
27047a6e288dSDaniel Borkmann 		}
27057a6e288dSDaniel Borkmann 	} else {
27067a6e288dSDaniel Borkmann 		 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
27077a6e288dSDaniel Borkmann 	}
27083de03596SJohn Fastabend 
270963d75463SPaolo Abeni 	/* the caller pre-fetches from skb->data and reserves for the mac hdr */
27103de03596SJohn Fastabend 	if (likely(skb))
271163d75463SPaolo Abeni 		skb_reserve(skb, extralen - 16);
27127a6e288dSDaniel Borkmann 
27137a6e288dSDaniel Borkmann 	return skb;
27147a6e288dSDaniel Borkmann }
27157a6e288dSDaniel Borkmann 
27161da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
27171da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
27181da177e4SLinus Torvalds {
27191da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
27201da177e4SLinus Torvalds 	__u8 *eth;
27211da177e4SLinus Torvalds 	struct udphdr *udph;
27221da177e4SLinus Torvalds 	int datalen, iplen;
27231da177e4SLinus Torvalds 	struct iphdr *iph;
2724d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IP);
2725ca6549afSSteven Whitehouse 	__be32 *mpls;
272634954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
272734954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
272834954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
272934954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2730fd2ea0a7SDavid S. Miller 	u16 queue_map;
2731ca6549afSSteven Whitehouse 
2732ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2733d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
27341da177e4SLinus Torvalds 
273534954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2736d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
273734954ddcSFrancesco Fondelli 
273864053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
273964053beeSRobert Olsson 	 * fields.
274064053beeSRobert Olsson 	 */
274164053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
2742eb589063SJunchang Wang 	queue_map = pkt_dev->cur_queue_map;
274364053beeSRobert Olsson 
274463d75463SPaolo Abeni 	skb = pktgen_alloc_skb(odev, pkt_dev);
27451da177e4SLinus Torvalds 	if (!skb) {
27461da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
27471da177e4SLinus Torvalds 		return NULL;
27481da177e4SLinus Torvalds 	}
27491da177e4SLinus Torvalds 
27507a6e288dSDaniel Borkmann 	prefetchw(skb->data);
275163d75463SPaolo Abeni 	skb_reserve(skb, 16);
27521da177e4SLinus Torvalds 
27531da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
2754d58ff351SJohannes Berg 	eth = skb_push(skb, 14);
27554df864c1SJohannes Berg 	mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32));
2756ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2757ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
275834954ddcSFrancesco Fondelli 
275934954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
276034954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
27614df864c1SJohannes Berg 			svlan_tci = skb_put(skb, sizeof(__be16));
27620f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
27630f37c605SAl Viro 					       pkt_dev->svlan_cfi,
27640f37c605SAl Viro 					       pkt_dev->svlan_p);
27654df864c1SJohannes Berg 			svlan_encapsulated_proto = skb_put(skb,
27664df864c1SJohannes Berg 							   sizeof(__be16));
2767d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
276834954ddcSFrancesco Fondelli 		}
27694df864c1SJohannes Berg 		vlan_tci = skb_put(skb, sizeof(__be16));
27700f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
27710f37c605SAl Viro 				      pkt_dev->vlan_cfi,
27720f37c605SAl Viro 				      pkt_dev->vlan_p);
27734df864c1SJohannes Berg 		vlan_encapsulated_proto = skb_put(skb, sizeof(__be16));
2774d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IP);
277534954ddcSFrancesco Fondelli 	}
277634954ddcSFrancesco Fondelli 
2777c145aeb3SZhang Shengju 	skb_reset_mac_header(skb);
2778525cebedSThomas Graf 	skb_set_network_header(skb, skb->len);
27794df864c1SJohannes Berg 	iph = skb_put(skb, sizeof(struct iphdr));
2780525cebedSThomas Graf 
2781525cebedSThomas Graf 	skb_set_transport_header(skb, skb->len);
27824df864c1SJohannes Berg 	udph = skb_put(skb, sizeof(struct udphdr));
2783fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
27849e50e3acSJohn Fastabend 	skb->priority = pkt_dev->skb_priority;
27859e50e3acSJohn Fastabend 
27861da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2787252e3346SAl Viro 	*(__be16 *) & eth[12] = protocol;
27881da177e4SLinus Torvalds 
2789ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2790ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
279116dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
27926af773e7SNishank Trivedi 	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr))
27931da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
27941da177e4SLinus Torvalds 
27951da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
27961da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
27971da177e4SLinus Torvalds 	udph->len = htons(datalen + 8);	/* DATA + udphdr */
2798c26bf4a5SThomas Graf 	udph->check = 0;
27991da177e4SLinus Torvalds 
28001da177e4SLinus Torvalds 	iph->ihl = 5;
28011da177e4SLinus Torvalds 	iph->version = 4;
28021da177e4SLinus Torvalds 	iph->ttl = 32;
28031ca7768cSFrancesco Fondelli 	iph->tos = pkt_dev->tos;
28041da177e4SLinus Torvalds 	iph->protocol = IPPROTO_UDP;	/* UDP */
28051da177e4SLinus Torvalds 	iph->saddr = pkt_dev->cur_saddr;
28061da177e4SLinus Torvalds 	iph->daddr = pkt_dev->cur_daddr;
280766ed1e5eSEric Dumazet 	iph->id = htons(pkt_dev->ip_id);
280866ed1e5eSEric Dumazet 	pkt_dev->ip_id++;
28091da177e4SLinus Torvalds 	iph->frag_off = 0;
28101da177e4SLinus Torvalds 	iplen = 20 + 8 + datalen;
28111da177e4SLinus Torvalds 	iph->tot_len = htons(iplen);
281203c633e7SThomas Graf 	ip_send_check(iph);
2813ca6549afSSteven Whitehouse 	skb->protocol = protocol;
28141da177e4SLinus Torvalds 	skb->dev = odev;
28151da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
2816c26bf4a5SThomas Graf 
28177744b5f3SSabrina Dubroca 	pktgen_finalize_skb(pkt_dev, skb, datalen);
28187744b5f3SSabrina Dubroca 
2819c26bf4a5SThomas Graf 	if (!(pkt_dev->flags & F_UDPCSUM)) {
2820c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_NONE;
2821c8cd0989STom Herbert 	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) {
2822c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_PARTIAL;
2823c26bf4a5SThomas Graf 		skb->csum = 0;
28247744b5f3SSabrina Dubroca 		udp4_hwcsum(skb, iph->saddr, iph->daddr);
2825c26bf4a5SThomas Graf 	} else {
28267744b5f3SSabrina Dubroca 		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0);
2827c26bf4a5SThomas Graf 
2828c26bf4a5SThomas Graf 		/* add protocol-dependent pseudo-header */
28297744b5f3SSabrina Dubroca 		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
2830c26bf4a5SThomas Graf 						datalen + 8, IPPROTO_UDP, csum);
2831c26bf4a5SThomas Graf 
2832c26bf4a5SThomas Graf 		if (udph->check == 0)
2833c26bf4a5SThomas Graf 			udph->check = CSUM_MANGLED_0;
2834c26bf4a5SThomas Graf 	}
2835c26bf4a5SThomas Graf 
2836a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2837a553e4a6SJamal Hadi Salim 	if (!process_ipsec(pkt_dev, skb, protocol))
2838a553e4a6SJamal Hadi Salim 		return NULL;
2839a553e4a6SJamal Hadi Salim #endif
2840a553e4a6SJamal Hadi Salim 
28411da177e4SLinus Torvalds 	return skb;
28421da177e4SLinus Torvalds }
28431da177e4SLinus Torvalds 
28441da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
28451da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
28461da177e4SLinus Torvalds {
28471da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
28481da177e4SLinus Torvalds 	__u8 *eth;
28491da177e4SLinus Torvalds 	struct udphdr *udph;
2850c26bf4a5SThomas Graf 	int datalen, udplen;
28511da177e4SLinus Torvalds 	struct ipv6hdr *iph;
2852d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IPV6);
2853ca6549afSSteven Whitehouse 	__be32 *mpls;
285434954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
285534954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
285634954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
285734954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2858fd2ea0a7SDavid S. Miller 	u16 queue_map;
2859ca6549afSSteven Whitehouse 
2860ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2861d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
28621da177e4SLinus Torvalds 
286334954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2864d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
286534954ddcSFrancesco Fondelli 
286664053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
286764053beeSRobert Olsson 	 * fields.
286864053beeSRobert Olsson 	 */
286964053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
2870eb589063SJunchang Wang 	queue_map = pkt_dev->cur_queue_map;
287164053beeSRobert Olsson 
287263d75463SPaolo Abeni 	skb = pktgen_alloc_skb(odev, pkt_dev);
28731da177e4SLinus Torvalds 	if (!skb) {
28741da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
28751da177e4SLinus Torvalds 		return NULL;
28761da177e4SLinus Torvalds 	}
28771da177e4SLinus Torvalds 
28787a6e288dSDaniel Borkmann 	prefetchw(skb->data);
28791da177e4SLinus Torvalds 	skb_reserve(skb, 16);
28801da177e4SLinus Torvalds 
28811da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
2882d58ff351SJohannes Berg 	eth = skb_push(skb, 14);
28834df864c1SJohannes Berg 	mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32));
2884ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2885ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
288634954ddcSFrancesco Fondelli 
288734954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
288834954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
28894df864c1SJohannes Berg 			svlan_tci = skb_put(skb, sizeof(__be16));
28900f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
28910f37c605SAl Viro 					       pkt_dev->svlan_cfi,
28920f37c605SAl Viro 					       pkt_dev->svlan_p);
28934df864c1SJohannes Berg 			svlan_encapsulated_proto = skb_put(skb,
28944df864c1SJohannes Berg 							   sizeof(__be16));
2895d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
289634954ddcSFrancesco Fondelli 		}
28974df864c1SJohannes Berg 		vlan_tci = skb_put(skb, sizeof(__be16));
28980f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
28990f37c605SAl Viro 				      pkt_dev->vlan_cfi,
29000f37c605SAl Viro 				      pkt_dev->vlan_p);
29014df864c1SJohannes Berg 		vlan_encapsulated_proto = skb_put(skb, sizeof(__be16));
2902d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
290334954ddcSFrancesco Fondelli 	}
290434954ddcSFrancesco Fondelli 
2905c145aeb3SZhang Shengju 	skb_reset_mac_header(skb);
2906525cebedSThomas Graf 	skb_set_network_header(skb, skb->len);
29074df864c1SJohannes Berg 	iph = skb_put(skb, sizeof(struct ipv6hdr));
2908525cebedSThomas Graf 
2909525cebedSThomas Graf 	skb_set_transport_header(skb, skb->len);
29104df864c1SJohannes Berg 	udph = skb_put(skb, sizeof(struct udphdr));
2911fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
29129e50e3acSJohn Fastabend 	skb->priority = pkt_dev->skb_priority;
29131da177e4SLinus Torvalds 
29141da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2915252e3346SAl Viro 	*(__be16 *) &eth[12] = protocol;
29161da177e4SLinus Torvalds 
2917ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2918ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 -
2919ca6549afSSteven Whitehouse 		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
292016dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
29211da177e4SLinus Torvalds 
29225aa8b572SAmerigo Wang 	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) {
29231da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
2924e87cc472SJoe Perches 		net_info_ratelimited("increased datalen to %d\n", datalen);
29251da177e4SLinus Torvalds 	}
29261da177e4SLinus Torvalds 
2927c26bf4a5SThomas Graf 	udplen = datalen + sizeof(struct udphdr);
29281da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
29291da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
2930c26bf4a5SThomas Graf 	udph->len = htons(udplen);
2931c26bf4a5SThomas Graf 	udph->check = 0;
29321da177e4SLinus Torvalds 
2933d5f1ce9aSStephen Hemminger 	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
29341da177e4SLinus Torvalds 
29351ca7768cSFrancesco Fondelli 	if (pkt_dev->traffic_class) {
29361ca7768cSFrancesco Fondelli 		/* Version + traffic class + flow (0) */
2937252e3346SAl Viro 		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
29381ca7768cSFrancesco Fondelli 	}
29391ca7768cSFrancesco Fondelli 
29401da177e4SLinus Torvalds 	iph->hop_limit = 32;
29411da177e4SLinus Torvalds 
2942c26bf4a5SThomas Graf 	iph->payload_len = htons(udplen);
29431da177e4SLinus Torvalds 	iph->nexthdr = IPPROTO_UDP;
29441da177e4SLinus Torvalds 
29454e3fd7a0SAlexey Dobriyan 	iph->daddr = pkt_dev->cur_in6_daddr;
29464e3fd7a0SAlexey Dobriyan 	iph->saddr = pkt_dev->cur_in6_saddr;
29471da177e4SLinus Torvalds 
2948ca6549afSSteven Whitehouse 	skb->protocol = protocol;
29491da177e4SLinus Torvalds 	skb->dev = odev;
29501da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
29511da177e4SLinus Torvalds 
29527744b5f3SSabrina Dubroca 	pktgen_finalize_skb(pkt_dev, skb, datalen);
29537744b5f3SSabrina Dubroca 
2954c26bf4a5SThomas Graf 	if (!(pkt_dev->flags & F_UDPCSUM)) {
2955c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_NONE;
2956c8cd0989STom Herbert 	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) {
2957c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_PARTIAL;
2958c26bf4a5SThomas Graf 		skb->csum_start = skb_transport_header(skb) - skb->head;
2959c26bf4a5SThomas Graf 		skb->csum_offset = offsetof(struct udphdr, check);
2960c26bf4a5SThomas Graf 		udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
2961c26bf4a5SThomas Graf 	} else {
29627744b5f3SSabrina Dubroca 		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0);
2963c26bf4a5SThomas Graf 
2964c26bf4a5SThomas Graf 		/* add protocol-dependent pseudo-header */
2965c26bf4a5SThomas Graf 		udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);
2966c26bf4a5SThomas Graf 
2967c26bf4a5SThomas Graf 		if (udph->check == 0)
2968c26bf4a5SThomas Graf 			udph->check = CSUM_MANGLED_0;
2969c26bf4a5SThomas Graf 	}
2970c26bf4a5SThomas Graf 
29711da177e4SLinus Torvalds 	return skb;
29721da177e4SLinus Torvalds }
29731da177e4SLinus Torvalds 
2974475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev,
29751da177e4SLinus Torvalds 				   struct pktgen_dev *pkt_dev)
29761da177e4SLinus Torvalds {
29771da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
29781da177e4SLinus Torvalds 		return fill_packet_ipv6(odev, pkt_dev);
29791da177e4SLinus Torvalds 	else
29801da177e4SLinus Torvalds 		return fill_packet_ipv4(odev, pkt_dev);
29811da177e4SLinus Torvalds }
29821da177e4SLinus Torvalds 
29831da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
29841da177e4SLinus Torvalds {
29851da177e4SLinus Torvalds 	pkt_dev->seq_num = 1;
29861da177e4SLinus Torvalds 	pkt_dev->idle_acc = 0;
29871da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
29881da177e4SLinus Torvalds 	pkt_dev->tx_bytes = 0;
29891da177e4SLinus Torvalds 	pkt_dev->errors = 0;
29901da177e4SLinus Torvalds }
29911da177e4SLinus Torvalds 
29921da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */
29931da177e4SLinus Torvalds 
29941da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t)
29951da177e4SLinus Torvalds {
2996c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
29971da177e4SLinus Torvalds 	int started = 0;
29981da177e4SLinus Torvalds 
2999f9467eaeSJoe Perches 	func_enter();
30001da177e4SLinus Torvalds 
30018788370aSJesper Dangaard Brouer 	rcu_read_lock();
30028788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
30031da177e4SLinus Torvalds 
30041da177e4SLinus Torvalds 		/*
30051da177e4SLinus Torvalds 		 * setup odev and create initial packet.
30061da177e4SLinus Torvalds 		 */
30071da177e4SLinus Torvalds 		pktgen_setup_inject(pkt_dev);
30081da177e4SLinus Torvalds 
30091da177e4SLinus Torvalds 		if (pkt_dev->odev) {
30101da177e4SLinus Torvalds 			pktgen_clear_counters(pkt_dev);
30111da177e4SLinus Torvalds 			pkt_dev->skb = NULL;
3012398f382cSDaniel Borkmann 			pkt_dev->started_at = pkt_dev->next_tx = ktime_get();
3013fd29cf72SStephen Hemminger 
301416dab72fSJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
30151da177e4SLinus Torvalds 
30161da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Starting");
30178788370aSJesper Dangaard Brouer 			pkt_dev->running = 1;	/* Cranke yeself! */
30181da177e4SLinus Torvalds 			started++;
3019222f1806SLuiz Capitulino 		} else
30201da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Error starting");
30211da177e4SLinus Torvalds 	}
30228788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3023222f1806SLuiz Capitulino 	if (started)
3024222f1806SLuiz Capitulino 		t->control &= ~(T_STOP);
30251da177e4SLinus Torvalds }
30261da177e4SLinus Torvalds 
3027*cda9de0bSYejune Deng static void pktgen_handle_all_threads(struct pktgen_net *pn, u32 flags)
30281da177e4SLinus Torvalds {
3029cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
30301da177e4SLinus Torvalds 
30316146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3032cdcdbe0bSLuiz Capitulino 
30334e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
3034*cda9de0bSYejune Deng 		t->control |= (flags);
3035cdcdbe0bSLuiz Capitulino 
30366146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
30371da177e4SLinus Torvalds }
30381da177e4SLinus Torvalds 
3039*cda9de0bSYejune Deng static void pktgen_stop_all_threads(struct pktgen_net *pn)
3040*cda9de0bSYejune Deng {
3041*cda9de0bSYejune Deng 	func_enter();
3042*cda9de0bSYejune Deng 
3043*cda9de0bSYejune Deng 	pktgen_handle_all_threads(pn, T_STOP);
3044*cda9de0bSYejune Deng }
3045*cda9de0bSYejune Deng 
3046648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t)
30471da177e4SLinus Torvalds {
3048648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
30491da177e4SLinus Torvalds 
30508788370aSJesper Dangaard Brouer 	rcu_read_lock();
30518788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
30528788370aSJesper Dangaard Brouer 		if (pkt_dev->running) {
30538788370aSJesper Dangaard Brouer 			rcu_read_unlock();
3054648fda74SStephen Hemminger 			return 1;
30558788370aSJesper Dangaard Brouer 		}
30568788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3057648fda74SStephen Hemminger 	return 0;
30581da177e4SLinus Torvalds }
30591da177e4SLinus Torvalds 
30601da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t)
30611da177e4SLinus Torvalds {
30621da177e4SLinus Torvalds 	while (thread_is_running(t)) {
30631da177e4SLinus Torvalds 
3064720f1de4SPaolo Abeni 		/* note: 't' will still be around even after the unlock/lock
3065720f1de4SPaolo Abeni 		 * cycle because pktgen_thread threads are only cleared at
3066720f1de4SPaolo Abeni 		 * net exit
3067720f1de4SPaolo Abeni 		 */
3068720f1de4SPaolo Abeni 		mutex_unlock(&pktgen_thread_lock);
30691da177e4SLinus Torvalds 		msleep_interruptible(100);
3070720f1de4SPaolo Abeni 		mutex_lock(&pktgen_thread_lock);
30711da177e4SLinus Torvalds 
30721da177e4SLinus Torvalds 		if (signal_pending(current))
30731da177e4SLinus Torvalds 			goto signal;
30741da177e4SLinus Torvalds 	}
30751da177e4SLinus Torvalds 	return 1;
30761da177e4SLinus Torvalds signal:
30771da177e4SLinus Torvalds 	return 0;
30781da177e4SLinus Torvalds }
30791da177e4SLinus Torvalds 
30804e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
30811da177e4SLinus Torvalds {
3082cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
30831da177e4SLinus Torvalds 	int sig = 1;
30841da177e4SLinus Torvalds 
3085720f1de4SPaolo Abeni 	/* prevent from racing with rmmod */
3086720f1de4SPaolo Abeni 	if (!try_module_get(THIS_MODULE))
3087720f1de4SPaolo Abeni 		return sig;
3088720f1de4SPaolo Abeni 
30896146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3090cdcdbe0bSLuiz Capitulino 
30914e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
30921da177e4SLinus Torvalds 		sig = pktgen_wait_thread_run(t);
3093222f1806SLuiz Capitulino 		if (sig == 0)
3094222f1806SLuiz Capitulino 			break;
30951da177e4SLinus Torvalds 	}
3096cdcdbe0bSLuiz Capitulino 
3097cdcdbe0bSLuiz Capitulino 	if (sig == 0)
30984e58a027SCong Wang 		list_for_each_entry(t, &pn->pktgen_threads, th_list)
30991da177e4SLinus Torvalds 			t->control |= (T_STOP);
3100cdcdbe0bSLuiz Capitulino 
31016146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
3102720f1de4SPaolo Abeni 	module_put(THIS_MODULE);
31031da177e4SLinus Torvalds 	return sig;
31041da177e4SLinus Torvalds }
31051da177e4SLinus Torvalds 
31064e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn)
31071da177e4SLinus Torvalds {
3108f9467eaeSJoe Perches 	func_enter();
31091da177e4SLinus Torvalds 
3110*cda9de0bSYejune Deng 	pktgen_handle_all_threads(pn, T_RUN);
31111da177e4SLinus Torvalds 
311263adc6fbSStephen Hemminger 	/* Propagate thread->control  */
311363adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
31141da177e4SLinus Torvalds 
31154e58a027SCong Wang 	pktgen_wait_all_threads_run(pn);
31161da177e4SLinus Torvalds }
31171da177e4SLinus Torvalds 
31184e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn)
3119eb37b41cSJesse Brandeburg {
3120f9467eaeSJoe Perches 	func_enter();
3121eb37b41cSJesse Brandeburg 
3122*cda9de0bSYejune Deng 	pktgen_handle_all_threads(pn, T_REMDEVALL);
3123eb37b41cSJesse Brandeburg 
312463adc6fbSStephen Hemminger 	/* Propagate thread->control  */
312563adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
3126eb37b41cSJesse Brandeburg 
31274e58a027SCong Wang 	pktgen_wait_all_threads_run(pn);
3128eb37b41cSJesse Brandeburg }
3129eb37b41cSJesse Brandeburg 
31301da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
31311da177e4SLinus Torvalds {
3132fd29cf72SStephen Hemminger 	__u64 bps, mbps, pps;
31331da177e4SLinus Torvalds 	char *p = pkt_dev->result;
3134fd29cf72SStephen Hemminger 	ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
3135fd29cf72SStephen Hemminger 				    pkt_dev->started_at);
3136fd29cf72SStephen Hemminger 	ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
31371da177e4SLinus Torvalds 
313803a14ab1SDaniel Turull 	p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
3139fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(elapsed),
3140fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
3141fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(idle),
31421da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->sofar,
31431da177e4SLinus Torvalds 		     pkt_dev->cur_pkt_size, nr_frags);
31441da177e4SLinus Torvalds 
3145fd29cf72SStephen Hemminger 	pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
3146fd29cf72SStephen Hemminger 			ktime_to_ns(elapsed));
31471da177e4SLinus Torvalds 
31481da177e4SLinus Torvalds 	bps = pps * 8 * pkt_dev->cur_pkt_size;
31491da177e4SLinus Torvalds 
31501da177e4SLinus Torvalds 	mbps = bps;
31511da177e4SLinus Torvalds 	do_div(mbps, 1000000);
31521da177e4SLinus Torvalds 	p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
31531da177e4SLinus Torvalds 		     (unsigned long long)pps,
31541da177e4SLinus Torvalds 		     (unsigned long long)mbps,
31551da177e4SLinus Torvalds 		     (unsigned long long)bps,
31561da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->errors);
31571da177e4SLinus Torvalds }
31581da177e4SLinus Torvalds 
31591da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */
31601da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
31611da177e4SLinus Torvalds {
3162222f1806SLuiz Capitulino 	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
31631da177e4SLinus Torvalds 
31641da177e4SLinus Torvalds 	if (!pkt_dev->running) {
3165294a0b7fSJoe Perches 		pr_warn("interface: %s is already stopped\n",
3166f9467eaeSJoe Perches 			pkt_dev->odevname);
31671da177e4SLinus Torvalds 		return -EINVAL;
31681da177e4SLinus Torvalds 	}
31691da177e4SLinus Torvalds 
31708788370aSJesper Dangaard Brouer 	pkt_dev->running = 0;
31713bda06a3SStephen Hemminger 	kfree_skb(pkt_dev->skb);
31723bda06a3SStephen Hemminger 	pkt_dev->skb = NULL;
3173398f382cSDaniel Borkmann 	pkt_dev->stopped_at = ktime_get();
31741da177e4SLinus Torvalds 
317595ed63f7SArthur Kepner 	show_results(pkt_dev, nr_frags);
31761da177e4SLinus Torvalds 
31771da177e4SLinus Torvalds 	return 0;
31781da177e4SLinus Torvalds }
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
31811da177e4SLinus Torvalds {
3182c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev, *best = NULL;
31831da177e4SLinus Torvalds 
31848788370aSJesper Dangaard Brouer 	rcu_read_lock();
31858788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3186c26a8016SLuiz Capitulino 		if (!pkt_dev->running)
3187222f1806SLuiz Capitulino 			continue;
3188222f1806SLuiz Capitulino 		if (best == NULL)
3189c26a8016SLuiz Capitulino 			best = pkt_dev;
3190398f382cSDaniel Borkmann 		else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0)
3191c26a8016SLuiz Capitulino 			best = pkt_dev;
31921da177e4SLinus Torvalds 	}
31938788370aSJesper Dangaard Brouer 	rcu_read_unlock();
31948788370aSJesper Dangaard Brouer 
31951da177e4SLinus Torvalds 	return best;
31961da177e4SLinus Torvalds }
31971da177e4SLinus Torvalds 
3198222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t)
3199222f1806SLuiz Capitulino {
3200c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
32011da177e4SLinus Torvalds 
3202f9467eaeSJoe Perches 	func_enter();
32031da177e4SLinus Torvalds 
32048788370aSJesper Dangaard Brouer 	rcu_read_lock();
32051da177e4SLinus Torvalds 
32068788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3207c26a8016SLuiz Capitulino 		pktgen_stop_device(pkt_dev);
320895ed63f7SArthur Kepner 	}
320995ed63f7SArthur Kepner 
32108788370aSJesper Dangaard Brouer 	rcu_read_unlock();
321195ed63f7SArthur Kepner }
321295ed63f7SArthur Kepner 
321395ed63f7SArthur Kepner /*
321495ed63f7SArthur Kepner  * one of our devices needs to be removed - find it
321595ed63f7SArthur Kepner  * and remove it
321695ed63f7SArthur Kepner  */
321795ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t)
321895ed63f7SArthur Kepner {
3219c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3220c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
322195ed63f7SArthur Kepner 
3222f9467eaeSJoe Perches 	func_enter();
322395ed63f7SArthur Kepner 
3224c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3225c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
322695ed63f7SArthur Kepner 
3227222f1806SLuiz Capitulino 		if (!cur->removal_mark)
3228222f1806SLuiz Capitulino 			continue;
322995ed63f7SArthur Kepner 
323095ed63f7SArthur Kepner 		kfree_skb(cur->skb);
323195ed63f7SArthur Kepner 		cur->skb = NULL;
323295ed63f7SArthur Kepner 
323395ed63f7SArthur Kepner 		pktgen_remove_device(t, cur);
323495ed63f7SArthur Kepner 
323595ed63f7SArthur Kepner 		break;
323695ed63f7SArthur Kepner 	}
32371da177e4SLinus Torvalds }
32381da177e4SLinus Torvalds 
32391da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t)
32401da177e4SLinus Torvalds {
3241c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3242c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
32431da177e4SLinus Torvalds 
3244f9467eaeSJoe Perches 	func_enter();
3245f9467eaeSJoe Perches 
32461da177e4SLinus Torvalds 	/* Remove all devices, free mem */
32471da177e4SLinus Torvalds 
3248c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3249c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
325095ed63f7SArthur Kepner 
325195ed63f7SArthur Kepner 		kfree_skb(cur->skb);
325295ed63f7SArthur Kepner 		cur->skb = NULL;
325395ed63f7SArthur Kepner 
32541da177e4SLinus Torvalds 		pktgen_remove_device(t, cur);
32551da177e4SLinus Torvalds 	}
32561da177e4SLinus Torvalds }
32571da177e4SLinus Torvalds 
32581da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t)
32591da177e4SLinus Torvalds {
32601da177e4SLinus Torvalds 	/* Remove from the thread list */
32614e58a027SCong Wang 	remove_proc_entry(t->tsk->comm, t->net->proc_dir);
32621da177e4SLinus Torvalds }
32631da177e4SLinus Torvalds 
3264ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev)
32653791decbSStephen Hemminger {
3266398f382cSDaniel Borkmann 	ktime_t idle_start = ktime_get();
32673791decbSStephen Hemminger 	schedule();
3268398f382cSDaniel Borkmann 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
32693791decbSStephen Hemminger }
32703791decbSStephen Hemminger 
3271ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
3272ef87979cSStephen Hemminger {
3273398f382cSDaniel Borkmann 	ktime_t idle_start = ktime_get();
3274ef87979cSStephen Hemminger 
327563354797SReshetova, Elena 	while (refcount_read(&(pkt_dev->skb->users)) != 1) {
3276ef87979cSStephen Hemminger 		if (signal_pending(current))
3277ef87979cSStephen Hemminger 			break;
3278ef87979cSStephen Hemminger 
3279ef87979cSStephen Hemminger 		if (need_resched())
3280ef87979cSStephen Hemminger 			pktgen_resched(pkt_dev);
3281ef87979cSStephen Hemminger 		else
3282ef87979cSStephen Hemminger 			cpu_relax();
3283ef87979cSStephen Hemminger 	}
3284398f382cSDaniel Borkmann 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
3285ef87979cSStephen Hemminger }
3286fd29cf72SStephen Hemminger 
3287475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev)
32881da177e4SLinus Torvalds {
32896aa7de05SMark Rutland 	unsigned int burst = READ_ONCE(pkt_dev->burst);
329000829823SStephen Hemminger 	struct net_device *odev = pkt_dev->odev;
3291fd2ea0a7SDavid S. Miller 	struct netdev_queue *txq;
329262f64aedSAlexei Starovoitov 	struct sk_buff *skb;
32931da177e4SLinus Torvalds 	int ret;
32941da177e4SLinus Torvalds 
3295ef87979cSStephen Hemminger 	/* If device is offline, then don't send */
3296ef87979cSStephen Hemminger 	if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) {
32971da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
32983791decbSStephen Hemminger 		return;
32991da177e4SLinus Torvalds 	}
33001da177e4SLinus Torvalds 
3301ef87979cSStephen Hemminger 	/* This is max DELAY, this has special meaning of
3302ef87979cSStephen Hemminger 	 * "never transmit"
3303ef87979cSStephen Hemminger 	 */
3304ef87979cSStephen Hemminger 	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
3305398f382cSDaniel Borkmann 		pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX);
3306ef87979cSStephen Hemminger 		return;
3307ef87979cSStephen Hemminger 	}
3308ef87979cSStephen Hemminger 
3309ef87979cSStephen Hemminger 	/* If no skb or clone count exhausted then get new one */
33107d7bb1cfSStephen Hemminger 	if (!pkt_dev->skb || (pkt_dev->last_ok &&
33117d7bb1cfSStephen Hemminger 			      ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
33121da177e4SLinus Torvalds 		/* build a new pkt */
33131da177e4SLinus Torvalds 		kfree_skb(pkt_dev->skb);
33141da177e4SLinus Torvalds 
33151da177e4SLinus Torvalds 		pkt_dev->skb = fill_packet(odev, pkt_dev);
33161da177e4SLinus Torvalds 		if (pkt_dev->skb == NULL) {
3317f9467eaeSJoe Perches 			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
33181da177e4SLinus Torvalds 			schedule();
33191da177e4SLinus Torvalds 			pkt_dev->clone_count--;	/* back out increment, OOM */
33203791decbSStephen Hemminger 			return;
33211da177e4SLinus Torvalds 		}
3322baac8564SEric Dumazet 		pkt_dev->last_pkt_size = pkt_dev->skb->len;
33231da177e4SLinus Torvalds 		pkt_dev->clone_count = 0;	/* reset counter */
33241da177e4SLinus Torvalds 	}
33251da177e4SLinus Torvalds 
3326ef87979cSStephen Hemminger 	if (pkt_dev->delay && pkt_dev->last_ok)
3327ef87979cSStephen Hemminger 		spin(pkt_dev, pkt_dev->next_tx);
3328ef87979cSStephen Hemminger 
332962f64aedSAlexei Starovoitov 	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) {
333062f64aedSAlexei Starovoitov 		skb = pkt_dev->skb;
333162f64aedSAlexei Starovoitov 		skb->protocol = eth_type_trans(skb, skb->dev);
333263354797SReshetova, Elena 		refcount_add(burst, &skb->users);
333362f64aedSAlexei Starovoitov 		local_bh_disable();
333462f64aedSAlexei Starovoitov 		do {
333562f64aedSAlexei Starovoitov 			ret = netif_receive_skb(skb);
333662f64aedSAlexei Starovoitov 			if (ret == NET_RX_DROP)
333762f64aedSAlexei Starovoitov 				pkt_dev->errors++;
333862f64aedSAlexei Starovoitov 			pkt_dev->sofar++;
333962f64aedSAlexei Starovoitov 			pkt_dev->seq_num++;
334063354797SReshetova, Elena 			if (refcount_read(&skb->users) != burst) {
334162f64aedSAlexei Starovoitov 				/* skb was queued by rps/rfs or taps,
334262f64aedSAlexei Starovoitov 				 * so cannot reuse this skb
334362f64aedSAlexei Starovoitov 				 */
334463354797SReshetova, Elena 				WARN_ON(refcount_sub_and_test(burst - 1, &skb->users));
334562f64aedSAlexei Starovoitov 				/* get out of the loop and wait
334662f64aedSAlexei Starovoitov 				 * until skb is consumed
334762f64aedSAlexei Starovoitov 				 */
334862f64aedSAlexei Starovoitov 				break;
334962f64aedSAlexei Starovoitov 			}
335062f64aedSAlexei Starovoitov 			/* skb was 'freed' by stack, so clean few
335162f64aedSAlexei Starovoitov 			 * bits and reuse it
335262f64aedSAlexei Starovoitov 			 */
33532c64605bSPablo Neira Ayuso 			skb_reset_redirect(skb);
335462f64aedSAlexei Starovoitov 		} while (--burst > 0);
335562f64aedSAlexei Starovoitov 		goto out; /* Skips xmit_mode M_START_XMIT */
33560967f244SJohn Fastabend 	} else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) {
33570967f244SJohn Fastabend 		local_bh_disable();
335863354797SReshetova, Elena 		refcount_inc(&pkt_dev->skb->users);
33590967f244SJohn Fastabend 
33600967f244SJohn Fastabend 		ret = dev_queue_xmit(pkt_dev->skb);
33610967f244SJohn Fastabend 		switch (ret) {
33620967f244SJohn Fastabend 		case NET_XMIT_SUCCESS:
33630967f244SJohn Fastabend 			pkt_dev->sofar++;
33640967f244SJohn Fastabend 			pkt_dev->seq_num++;
33650967f244SJohn Fastabend 			pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
33660967f244SJohn Fastabend 			break;
33670967f244SJohn Fastabend 		case NET_XMIT_DROP:
33680967f244SJohn Fastabend 		case NET_XMIT_CN:
33690967f244SJohn Fastabend 		/* These are all valid return codes for a qdisc but
33700967f244SJohn Fastabend 		 * indicate packets are being dropped or will likely
33710967f244SJohn Fastabend 		 * be dropped soon.
33720967f244SJohn Fastabend 		 */
33730967f244SJohn Fastabend 		case NETDEV_TX_BUSY:
33740967f244SJohn Fastabend 		/* qdisc may call dev_hard_start_xmit directly in cases
33750967f244SJohn Fastabend 		 * where no queues exist e.g. loopback device, virtual
33760967f244SJohn Fastabend 		 * devices, etc. In this case we need to handle
33770967f244SJohn Fastabend 		 * NETDEV_TX_ codes.
33780967f244SJohn Fastabend 		 */
33790967f244SJohn Fastabend 		default:
33800967f244SJohn Fastabend 			pkt_dev->errors++;
33810967f244SJohn Fastabend 			net_info_ratelimited("%s xmit error: %d\n",
33820967f244SJohn Fastabend 					     pkt_dev->odevname, ret);
33830967f244SJohn Fastabend 			break;
33840967f244SJohn Fastabend 		}
33850967f244SJohn Fastabend 		goto out;
338662f64aedSAlexei Starovoitov 	}
338762f64aedSAlexei Starovoitov 
338810c51b56SDaniel Borkmann 	txq = skb_get_tx_queue(odev, pkt_dev->skb);
3389fd2ea0a7SDavid S. Miller 
33900f2eea4bSDaniel Borkmann 	local_bh_disable();
33910f2eea4bSDaniel Borkmann 
33920f2eea4bSDaniel Borkmann 	HARD_TX_LOCK(odev, txq, smp_processor_id());
33935b8db2f5SStephen Hemminger 
33946f25cd47SDaniel Borkmann 	if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) {
33950835acfeSEric Dumazet 		pkt_dev->last_ok = 0;
33960835acfeSEric Dumazet 		goto unlock;
33970835acfeSEric Dumazet 	}
339863354797SReshetova, Elena 	refcount_add(burst, &pkt_dev->skb->users);
339938b2cf29SAlexei Starovoitov 
340038b2cf29SAlexei Starovoitov xmit_more:
340138b2cf29SAlexei Starovoitov 	ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0);
3402ef87979cSStephen Hemminger 
34035b8db2f5SStephen Hemminger 	switch (ret) {
34045b8db2f5SStephen Hemminger 	case NETDEV_TX_OK:
34051da177e4SLinus Torvalds 		pkt_dev->last_ok = 1;
34061da177e4SLinus Torvalds 		pkt_dev->sofar++;
34071da177e4SLinus Torvalds 		pkt_dev->seq_num++;
3408baac8564SEric Dumazet 		pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
340938b2cf29SAlexei Starovoitov 		if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq))
341038b2cf29SAlexei Starovoitov 			goto xmit_more;
34115b8db2f5SStephen Hemminger 		break;
3412f466dba1SJohn Fastabend 	case NET_XMIT_DROP:
3413f466dba1SJohn Fastabend 	case NET_XMIT_CN:
3414f466dba1SJohn Fastabend 		/* skb has been consumed */
3415f466dba1SJohn Fastabend 		pkt_dev->errors++;
3416f466dba1SJohn Fastabend 		break;
34175b8db2f5SStephen Hemminger 	default: /* Drivers are not supposed to return other values! */
3418e87cc472SJoe Perches 		net_info_ratelimited("%s xmit error: %d\n",
3419e87cc472SJoe Perches 				     pkt_dev->odevname, ret);
34201da177e4SLinus Torvalds 		pkt_dev->errors++;
3421df561f66SGustavo A. R. Silva 		fallthrough;
34225b8db2f5SStephen Hemminger 	case NETDEV_TX_BUSY:
34235b8db2f5SStephen Hemminger 		/* Retry it next time */
342463354797SReshetova, Elena 		refcount_dec(&(pkt_dev->skb->users));
34251da177e4SLinus Torvalds 		pkt_dev->last_ok = 0;
34261da177e4SLinus Torvalds 	}
342738b2cf29SAlexei Starovoitov 	if (unlikely(burst))
342863354797SReshetova, Elena 		WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users));
34290835acfeSEric Dumazet unlock:
34300f2eea4bSDaniel Borkmann 	HARD_TX_UNLOCK(odev, txq);
34310f2eea4bSDaniel Borkmann 
343262f64aedSAlexei Starovoitov out:
34330f2eea4bSDaniel Borkmann 	local_bh_enable();
34341da177e4SLinus Torvalds 
34351da177e4SLinus Torvalds 	/* If pkt_dev->count is zero, then run forever */
34361da177e4SLinus Torvalds 	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
3437ef87979cSStephen Hemminger 		pktgen_wait_for_skb(pkt_dev);
34381da177e4SLinus Torvalds 
34391da177e4SLinus Torvalds 		/* Done with this */
34401da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
34411da177e4SLinus Torvalds 	}
34421da177e4SLinus Torvalds }
34431da177e4SLinus Torvalds 
34441da177e4SLinus Torvalds /*
34451da177e4SLinus Torvalds  * Main loop of the thread goes here
34461da177e4SLinus Torvalds  */
34471da177e4SLinus Torvalds 
3448ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg)
34491da177e4SLinus Torvalds {
34501da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
3451ee74baa7SDavid S. Miller 	struct pktgen_thread *t = arg;
34521da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
34531da177e4SLinus Torvalds 	int cpu = t->cpu;
34541da177e4SLinus Torvalds 
3455275b1e88SDi Zhu 	WARN_ON(smp_processor_id() != cpu);
34561da177e4SLinus Torvalds 
34571da177e4SLinus Torvalds 	init_waitqueue_head(&t->queue);
3458d3ede327SDenis V. Lunev 	complete(&t->start_done);
34591da177e4SLinus Torvalds 
3460f9467eaeSJoe Perches 	pr_debug("starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
34611da177e4SLinus Torvalds 
346283144186SRafael J. Wysocki 	set_freezable();
346383144186SRafael J. Wysocki 
3464ee74baa7SDavid S. Miller 	while (!kthread_should_stop()) {
3465ee74baa7SDavid S. Miller 		pkt_dev = next_to_run(t);
3466ee74baa7SDavid S. Miller 
3467ef87979cSStephen Hemminger 		if (unlikely(!pkt_dev && t->control == 0)) {
34684e58a027SCong Wang 			if (t->net->pktgen_exiting)
3469551eaff1SEric Dumazet 				break;
3470ef87979cSStephen Hemminger 			wait_event_interruptible_timeout(t->queue,
3471ef87979cSStephen Hemminger 							 t->control != 0,
3472ef87979cSStephen Hemminger 							 HZ/10);
34731b3f720bSRafael J. Wysocki 			try_to_freeze();
3474ef87979cSStephen Hemminger 			continue;
3475ee74baa7SDavid S. Miller 		}
34761da177e4SLinus Torvalds 
3477ef87979cSStephen Hemminger 		if (likely(pkt_dev)) {
34781da177e4SLinus Torvalds 			pktgen_xmit(pkt_dev);
34791da177e4SLinus Torvalds 
3480ef87979cSStephen Hemminger 			if (need_resched())
3481ef87979cSStephen Hemminger 				pktgen_resched(pkt_dev);
3482ef87979cSStephen Hemminger 			else
3483ef87979cSStephen Hemminger 				cpu_relax();
3484ef87979cSStephen Hemminger 		}
3485ef87979cSStephen Hemminger 
34861da177e4SLinus Torvalds 		if (t->control & T_STOP) {
34871da177e4SLinus Torvalds 			pktgen_stop(t);
34881da177e4SLinus Torvalds 			t->control &= ~(T_STOP);
34891da177e4SLinus Torvalds 		}
34901da177e4SLinus Torvalds 
34911da177e4SLinus Torvalds 		if (t->control & T_RUN) {
34921da177e4SLinus Torvalds 			pktgen_run(t);
34931da177e4SLinus Torvalds 			t->control &= ~(T_RUN);
34941da177e4SLinus Torvalds 		}
34951da177e4SLinus Torvalds 
349695ed63f7SArthur Kepner 		if (t->control & T_REMDEVALL) {
34971da177e4SLinus Torvalds 			pktgen_rem_all_ifs(t);
349895ed63f7SArthur Kepner 			t->control &= ~(T_REMDEVALL);
349995ed63f7SArthur Kepner 		}
350095ed63f7SArthur Kepner 
350195ed63f7SArthur Kepner 		if (t->control & T_REMDEV) {
350295ed63f7SArthur Kepner 			pktgen_rem_one_if(t);
35031da177e4SLinus Torvalds 			t->control &= ~(T_REMDEV);
35041da177e4SLinus Torvalds 		}
35051da177e4SLinus Torvalds 
350609fe3ef4SAndrew Morton 		try_to_freeze();
35071da177e4SLinus Torvalds 	}
35081da177e4SLinus Torvalds 
3509f9467eaeSJoe Perches 	pr_debug("%s stopping all device\n", t->tsk->comm);
35101da177e4SLinus Torvalds 	pktgen_stop(t);
35111da177e4SLinus Torvalds 
3512f9467eaeSJoe Perches 	pr_debug("%s removing all device\n", t->tsk->comm);
35131da177e4SLinus Torvalds 	pktgen_rem_all_ifs(t);
35141da177e4SLinus Torvalds 
3515f9467eaeSJoe Perches 	pr_debug("%s removing thread\n", t->tsk->comm);
35161da177e4SLinus Torvalds 	pktgen_rem_thread(t);
3517cdcdbe0bSLuiz Capitulino 
3518ee74baa7SDavid S. Miller 	return 0;
35191da177e4SLinus Torvalds }
35201da177e4SLinus Torvalds 
3521222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
35223e984840SEric Dumazet 					  const char *ifname, bool exact)
35231da177e4SLinus Torvalds {
3524c26a8016SLuiz Capitulino 	struct pktgen_dev *p, *pkt_dev = NULL;
35253e984840SEric Dumazet 	size_t len = strlen(ifname);
35261da177e4SLinus Torvalds 
35278788370aSJesper Dangaard Brouer 	rcu_read_lock();
35288788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(p, &t->if_list, list)
35293e984840SEric Dumazet 		if (strncmp(p->odevname, ifname, len) == 0) {
35303e984840SEric Dumazet 			if (p->odevname[len]) {
35313e984840SEric Dumazet 				if (exact || p->odevname[len] != '@')
35323e984840SEric Dumazet 					continue;
35333e984840SEric Dumazet 			}
3534c26a8016SLuiz Capitulino 			pkt_dev = p;
35351da177e4SLinus Torvalds 			break;
35361da177e4SLinus Torvalds 		}
35371da177e4SLinus Torvalds 
35388788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3539f9467eaeSJoe Perches 	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
35401da177e4SLinus Torvalds 	return pkt_dev;
35411da177e4SLinus Torvalds }
35421da177e4SLinus Torvalds 
35431da177e4SLinus Torvalds /*
35441da177e4SLinus Torvalds  * Adds a dev at front of if_list.
35451da177e4SLinus Torvalds  */
35461da177e4SLinus Torvalds 
3547222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t,
3548222f1806SLuiz Capitulino 			     struct pktgen_dev *pkt_dev)
35491da177e4SLinus Torvalds {
35501da177e4SLinus Torvalds 	int rv = 0;
35511da177e4SLinus Torvalds 
35528788370aSJesper Dangaard Brouer 	/* This function cannot be called concurrently, as its called
35538788370aSJesper Dangaard Brouer 	 * under pktgen_thread_lock mutex, but it can run from
35548788370aSJesper Dangaard Brouer 	 * userspace on another CPU than the kthread.  The if_lock()
35558788370aSJesper Dangaard Brouer 	 * is used here to sync with concurrent instances of
35568788370aSJesper Dangaard Brouer 	 * _rem_dev_from_if_list() invoked via kthread, which is also
35578788370aSJesper Dangaard Brouer 	 * updating the if_list */
35581da177e4SLinus Torvalds 	if_lock(t);
35591da177e4SLinus Torvalds 
35601da177e4SLinus Torvalds 	if (pkt_dev->pg_thread) {
3561f9467eaeSJoe Perches 		pr_err("ERROR: already assigned to a thread\n");
35621da177e4SLinus Torvalds 		rv = -EBUSY;
35631da177e4SLinus Torvalds 		goto out;
35641da177e4SLinus Torvalds 	}
3565c26a8016SLuiz Capitulino 
35661da177e4SLinus Torvalds 	pkt_dev->running = 0;
35678788370aSJesper Dangaard Brouer 	pkt_dev->pg_thread = t;
35688788370aSJesper Dangaard Brouer 	list_add_rcu(&pkt_dev->list, &t->if_list);
35691da177e4SLinus Torvalds 
35701da177e4SLinus Torvalds out:
35711da177e4SLinus Torvalds 	if_unlock(t);
35721da177e4SLinus Torvalds 	return rv;
35731da177e4SLinus Torvalds }
35741da177e4SLinus Torvalds 
35751da177e4SLinus Torvalds /* Called under thread lock */
35761da177e4SLinus Torvalds 
35771da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
35781da177e4SLinus Torvalds {
35791da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev;
358039df232fSStephen Hemminger 	int err;
35813291b9dbSEric Dumazet 	int node = cpu_to_node(t->cpu);
35821da177e4SLinus Torvalds 
35831da177e4SLinus Torvalds 	/* We don't allow a device to be on several threads */
35841da177e4SLinus Torvalds 
35854e58a027SCong Wang 	pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND);
3586d50a6b56SStephen Hemminger 	if (pkt_dev) {
3587f9467eaeSJoe Perches 		pr_err("ERROR: interface already used\n");
3588d50a6b56SStephen Hemminger 		return -EBUSY;
3589d50a6b56SStephen Hemminger 	}
35901da177e4SLinus Torvalds 
35913291b9dbSEric Dumazet 	pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node);
35921da177e4SLinus Torvalds 	if (!pkt_dev)
35931da177e4SLinus Torvalds 		return -ENOMEM;
35941da177e4SLinus Torvalds 
3595593f63b0SEric Dumazet 	strcpy(pkt_dev->odevname, ifname);
3596fd7becedSKees Cook 	pkt_dev->flows = vzalloc_node(array_size(MAX_CFLOWS,
3597fd7becedSKees Cook 						 sizeof(struct flow_state)),
35983291b9dbSEric Dumazet 				      node);
35991da177e4SLinus Torvalds 	if (pkt_dev->flows == NULL) {
36001da177e4SLinus Torvalds 		kfree(pkt_dev);
36011da177e4SLinus Torvalds 		return -ENOMEM;
36021da177e4SLinus Torvalds 	}
36031da177e4SLinus Torvalds 
360495ed63f7SArthur Kepner 	pkt_dev->removal_mark = 0;
36051da177e4SLinus Torvalds 	pkt_dev->nfrags = 0;
3606fd29cf72SStephen Hemminger 	pkt_dev->delay = pg_delay_d;
36071da177e4SLinus Torvalds 	pkt_dev->count = pg_count_d;
36081da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
36091da177e4SLinus Torvalds 	pkt_dev->udp_src_min = 9;	/* sink port */
36101da177e4SLinus Torvalds 	pkt_dev->udp_src_max = 9;
36111da177e4SLinus Torvalds 	pkt_dev->udp_dst_min = 9;
36121da177e4SLinus Torvalds 	pkt_dev->udp_dst_max = 9;
361334954ddcSFrancesco Fondelli 	pkt_dev->vlan_p = 0;
361434954ddcSFrancesco Fondelli 	pkt_dev->vlan_cfi = 0;
361534954ddcSFrancesco Fondelli 	pkt_dev->vlan_id = 0xffff;
361634954ddcSFrancesco Fondelli 	pkt_dev->svlan_p = 0;
361734954ddcSFrancesco Fondelli 	pkt_dev->svlan_cfi = 0;
361834954ddcSFrancesco Fondelli 	pkt_dev->svlan_id = 0xffff;
361938b2cf29SAlexei Starovoitov 	pkt_dev->burst = 1;
362098fa15f3SAnshuman Khandual 	pkt_dev->node = NUMA_NO_NODE;
362134954ddcSFrancesco Fondelli 
36224e58a027SCong Wang 	err = pktgen_setup_dev(t->net, pkt_dev, ifname);
362339df232fSStephen Hemminger 	if (err)
362439df232fSStephen Hemminger 		goto out1;
3625d8873315SNeil Horman 	if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
3626d8873315SNeil Horman 		pkt_dev->clone_skb = pg_clone_skb_d;
36271da177e4SLinus Torvalds 
36284e58a027SCong Wang 	pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir,
362997a32539SAlexey Dobriyan 					  &pktgen_if_proc_ops, pkt_dev);
363039df232fSStephen Hemminger 	if (!pkt_dev->entry) {
3631f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3632d50a6b56SStephen Hemminger 		       PG_PROC_DIR, ifname);
363339df232fSStephen Hemminger 		err = -EINVAL;
363439df232fSStephen Hemminger 		goto out2;
363539df232fSStephen Hemminger 	}
3636a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3637a553e4a6SJamal Hadi Salim 	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
3638a553e4a6SJamal Hadi Salim 	pkt_dev->ipsproto = IPPROTO_ESP;
3639cf93d47eSFan Du 
3640cf93d47eSFan Du 	/* xfrm tunnel mode needs additional dst to extract outter
3641cf93d47eSFan Du 	 * ip header protocol/ttl/id field, here creat a phony one.
3642cf93d47eSFan Du 	 * instead of looking for a valid rt, which definitely hurting
3643cf93d47eSFan Du 	 * performance under such circumstance.
3644cf93d47eSFan Du 	 */
3645cf93d47eSFan Du 	pkt_dev->dstops.family = AF_INET;
3646b6ca8bd5SDavid Miller 	pkt_dev->xdst.u.dst.dev = pkt_dev->odev;
3647b6ca8bd5SDavid Miller 	dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false);
3648b6ca8bd5SDavid Miller 	pkt_dev->xdst.child = &pkt_dev->xdst.u.dst;
3649b6ca8bd5SDavid Miller 	pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops;
3650a553e4a6SJamal Hadi Salim #endif
365139df232fSStephen Hemminger 
365239df232fSStephen Hemminger 	return add_dev_to_thread(t, pkt_dev);
365339df232fSStephen Hemminger out2:
365439df232fSStephen Hemminger 	dev_put(pkt_dev->odev);
365539df232fSStephen Hemminger out1:
3656a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3657a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3658a553e4a6SJamal Hadi Salim #endif
36591da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
36601da177e4SLinus Torvalds 	kfree(pkt_dev);
366139df232fSStephen Hemminger 	return err;
36621da177e4SLinus Torvalds }
36631da177e4SLinus Torvalds 
36644e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
36651da177e4SLinus Torvalds {
3666cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3667d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3668ee74baa7SDavid S. Miller 	struct task_struct *p;
36691da177e4SLinus Torvalds 
36703291b9dbSEric Dumazet 	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
36713291b9dbSEric Dumazet 			 cpu_to_node(cpu));
36721da177e4SLinus Torvalds 	if (!t) {
3673f9467eaeSJoe Perches 		pr_err("ERROR: out of memory, can't create new thread\n");
36741da177e4SLinus Torvalds 		return -ENOMEM;
36751da177e4SLinus Torvalds 	}
36761da177e4SLinus Torvalds 
36779a0b1e8bSEric Dumazet 	mutex_init(&t->if_lock);
36781da177e4SLinus Torvalds 	t->cpu = cpu;
36791da177e4SLinus Torvalds 
3680ee74baa7SDavid S. Miller 	INIT_LIST_HEAD(&t->if_list);
3681ee74baa7SDavid S. Miller 
36824e58a027SCong Wang 	list_add_tail(&t->th_list, &pn->pktgen_threads);
3683d3ede327SDenis V. Lunev 	init_completion(&t->start_done);
3684ee74baa7SDavid S. Miller 
368594dcf29aSEric Dumazet 	p = kthread_create_on_node(pktgen_thread_worker,
368694dcf29aSEric Dumazet 				   t,
368794dcf29aSEric Dumazet 				   cpu_to_node(cpu),
368894dcf29aSEric Dumazet 				   "kpktgend_%d", cpu);
3689ee74baa7SDavid S. Miller 	if (IS_ERR(p)) {
3690355db391SLeesoo Ahn 		pr_err("kthread_create_on_node() failed for cpu %d\n", t->cpu);
3691ee74baa7SDavid S. Miller 		list_del(&t->th_list);
3692ee74baa7SDavid S. Miller 		kfree(t);
3693ee74baa7SDavid S. Miller 		return PTR_ERR(p);
3694ee74baa7SDavid S. Miller 	}
3695ee74baa7SDavid S. Miller 	kthread_bind(p, cpu);
3696ee74baa7SDavid S. Miller 	t->tsk = p;
3697ee74baa7SDavid S. Miller 
36984e58a027SCong Wang 	pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir,
369997a32539SAlexey Dobriyan 			      &pktgen_thread_proc_ops, t);
3700d50a6b56SStephen Hemminger 	if (!pe) {
3701f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3702ee74baa7SDavid S. Miller 		       PG_PROC_DIR, t->tsk->comm);
3703ee74baa7SDavid S. Miller 		kthread_stop(p);
3704ee74baa7SDavid S. Miller 		list_del(&t->th_list);
37051da177e4SLinus Torvalds 		kfree(t);
37061da177e4SLinus Torvalds 		return -EINVAL;
37071da177e4SLinus Torvalds 	}
3708d50a6b56SStephen Hemminger 
37094e58a027SCong Wang 	t->net = pn;
37101fbe4b46SOleg Nesterov 	get_task_struct(p);
3711ee74baa7SDavid S. Miller 	wake_up_process(p);
3712d3ede327SDenis V. Lunev 	wait_for_completion(&t->start_done);
37131da177e4SLinus Torvalds 
37141da177e4SLinus Torvalds 	return 0;
37151da177e4SLinus Torvalds }
37161da177e4SLinus Torvalds 
37171da177e4SLinus Torvalds /*
37181da177e4SLinus Torvalds  * Removes a device from the thread if_list.
37191da177e4SLinus Torvalds  */
3720222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t,
3721222f1806SLuiz Capitulino 				  struct pktgen_dev *pkt_dev)
37221da177e4SLinus Torvalds {
3723c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3724c26a8016SLuiz Capitulino 	struct pktgen_dev *p;
37251da177e4SLinus Torvalds 
37268788370aSJesper Dangaard Brouer 	if_lock(t);
3727c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3728c26a8016SLuiz Capitulino 		p = list_entry(q, struct pktgen_dev, list);
3729c26a8016SLuiz Capitulino 		if (p == pkt_dev)
37308788370aSJesper Dangaard Brouer 			list_del_rcu(&p->list);
37311da177e4SLinus Torvalds 	}
37328788370aSJesper Dangaard Brouer 	if_unlock(t);
37331da177e4SLinus Torvalds }
37341da177e4SLinus Torvalds 
3735222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t,
3736222f1806SLuiz Capitulino 				struct pktgen_dev *pkt_dev)
37371da177e4SLinus Torvalds {
3738f9467eaeSJoe Perches 	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
37391da177e4SLinus Torvalds 
37401da177e4SLinus Torvalds 	if (pkt_dev->running) {
3741294a0b7fSJoe Perches 		pr_warn("WARNING: trying to remove a running interface, stopping it now\n");
37421da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
37431da177e4SLinus Torvalds 	}
37441da177e4SLinus Torvalds 
37451da177e4SLinus Torvalds 	/* Dis-associate from the interface */
37461da177e4SLinus Torvalds 
37471da177e4SLinus Torvalds 	if (pkt_dev->odev) {
37481da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
37491da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
37501da177e4SLinus Torvalds 	}
37511da177e4SLinus Torvalds 
37528788370aSJesper Dangaard Brouer 	/* Remove proc before if_list entry, because add_device uses
37538788370aSJesper Dangaard Brouer 	 * list to determine if interface already exist, avoid race
37548788370aSJesper Dangaard Brouer 	 * with proc_create_data() */
3755a8ca16eaSDavid Howells 	proc_remove(pkt_dev->entry);
37561da177e4SLinus Torvalds 
37578788370aSJesper Dangaard Brouer 	/* And update the thread if_list */
37588788370aSJesper Dangaard Brouer 	_rem_dev_from_if_list(t, pkt_dev);
37598788370aSJesper Dangaard Brouer 
3760a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3761a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3762a553e4a6SJamal Hadi Salim #endif
37631da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
376426ad7879SEric Dumazet 	if (pkt_dev->page)
376526ad7879SEric Dumazet 		put_page(pkt_dev->page);
37668788370aSJesper Dangaard Brouer 	kfree_rcu(pkt_dev, rcu);
37671da177e4SLinus Torvalds 	return 0;
37681da177e4SLinus Torvalds }
37691da177e4SLinus Torvalds 
37704e58a027SCong Wang static int __net_init pg_net_init(struct net *net)
37711da177e4SLinus Torvalds {
37724e58a027SCong Wang 	struct pktgen_net *pn = net_generic(net, pg_net_id);
3773d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
37744e58a027SCong Wang 	int cpu, ret = 0;
3775d50a6b56SStephen Hemminger 
37764e58a027SCong Wang 	pn->net = net;
37774e58a027SCong Wang 	INIT_LIST_HEAD(&pn->pktgen_threads);
37784e58a027SCong Wang 	pn->pktgen_exiting = false;
37794e58a027SCong Wang 	pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net);
37804e58a027SCong Wang 	if (!pn->proc_dir) {
37814e58a027SCong Wang 		pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR);
3782d50a6b56SStephen Hemminger 		return -ENODEV;
37831da177e4SLinus Torvalds 	}
378497a32539SAlexey Dobriyan 	pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_proc_ops);
37854e58a027SCong Wang 	if (pe == NULL) {
37864e58a027SCong Wang 		pr_err("cannot create %s procfs entry\n", PGCTRL);
37874e58a027SCong Wang 		ret = -EINVAL;
37884e58a027SCong Wang 		goto remove;
37894e58a027SCong Wang 	}
37901da177e4SLinus Torvalds 
3791670c02c2SJohn Hawkes 	for_each_online_cpu(cpu) {
37928024bb24SLuiz Capitulino 		int err;
37931da177e4SLinus Torvalds 
37944e58a027SCong Wang 		err = pktgen_create_thread(cpu, pn);
37958024bb24SLuiz Capitulino 		if (err)
37964e58a027SCong Wang 			pr_warn("Cannot create thread for cpu %d (%d)\n",
3797f9467eaeSJoe Perches 				   cpu, err);
37981da177e4SLinus Torvalds 	}
37998024bb24SLuiz Capitulino 
38004e58a027SCong Wang 	if (list_empty(&pn->pktgen_threads)) {
38014e58a027SCong Wang 		pr_err("Initialization failed for all threads\n");
3802ce14f894SWANG Cong 		ret = -ENODEV;
38034e58a027SCong Wang 		goto remove_entry;
38048024bb24SLuiz Capitulino 	}
38058024bb24SLuiz Capitulino 
38061da177e4SLinus Torvalds 	return 0;
3807ce14f894SWANG Cong 
38084e58a027SCong Wang remove_entry:
38094e58a027SCong Wang 	remove_proc_entry(PGCTRL, pn->proc_dir);
38104e58a027SCong Wang remove:
3811ece31ffdSGao feng 	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
3812ce14f894SWANG Cong 	return ret;
38131da177e4SLinus Torvalds }
38141da177e4SLinus Torvalds 
38154e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net)
38161da177e4SLinus Torvalds {
38174e58a027SCong Wang 	struct pktgen_net *pn = net_generic(net, pg_net_id);
3818cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3819cdcdbe0bSLuiz Capitulino 	struct list_head *q, *n;
3820d4b11335SEric Dumazet 	LIST_HEAD(list);
38211da177e4SLinus Torvalds 
38221da177e4SLinus Torvalds 	/* Stop all interfaces & threads */
38234e58a027SCong Wang 	pn->pktgen_exiting = true;
38241da177e4SLinus Torvalds 
3825c57b5468SEric Dumazet 	mutex_lock(&pktgen_thread_lock);
38264e58a027SCong Wang 	list_splice_init(&pn->pktgen_threads, &list);
3827c57b5468SEric Dumazet 	mutex_unlock(&pktgen_thread_lock);
3828c57b5468SEric Dumazet 
3829c57b5468SEric Dumazet 	list_for_each_safe(q, n, &list) {
3830cdcdbe0bSLuiz Capitulino 		t = list_entry(q, struct pktgen_thread, th_list);
3831c57b5468SEric Dumazet 		list_del(&t->th_list);
3832ee74baa7SDavid S. Miller 		kthread_stop(t->tsk);
38331fbe4b46SOleg Nesterov 		put_task_struct(t->tsk);
3834ee74baa7SDavid S. Miller 		kfree(t);
38351da177e4SLinus Torvalds 	}
38361da177e4SLinus Torvalds 
38374e58a027SCong Wang 	remove_proc_entry(PGCTRL, pn->proc_dir);
3838ece31ffdSGao feng 	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
38394e58a027SCong Wang }
38401da177e4SLinus Torvalds 
38414e58a027SCong Wang static struct pernet_operations pg_net_ops = {
38424e58a027SCong Wang 	.init = pg_net_init,
38434e58a027SCong Wang 	.exit = pg_net_exit,
38444e58a027SCong Wang 	.id   = &pg_net_id,
38454e58a027SCong Wang 	.size = sizeof(struct pktgen_net),
38464e58a027SCong Wang };
38474e58a027SCong Wang 
38484e58a027SCong Wang static int __init pg_init(void)
38494e58a027SCong Wang {
38504e58a027SCong Wang 	int ret = 0;
38514e58a027SCong Wang 
38524e58a027SCong Wang 	pr_info("%s", version);
38534e58a027SCong Wang 	ret = register_pernet_subsys(&pg_net_ops);
38544e58a027SCong Wang 	if (ret)
38554e58a027SCong Wang 		return ret;
38564e58a027SCong Wang 	ret = register_netdevice_notifier(&pktgen_notifier_block);
38574e58a027SCong Wang 	if (ret)
38584e58a027SCong Wang 		unregister_pernet_subsys(&pg_net_ops);
38594e58a027SCong Wang 
38604e58a027SCong Wang 	return ret;
38614e58a027SCong Wang }
38624e58a027SCong Wang 
38634e58a027SCong Wang static void __exit pg_cleanup(void)
38644e58a027SCong Wang {
38654e58a027SCong Wang 	unregister_netdevice_notifier(&pktgen_notifier_block);
38664e58a027SCong Wang 	unregister_pernet_subsys(&pg_net_ops);
38678788370aSJesper Dangaard Brouer 	/* Don't need rcu_barrier() due to use of kfree_rcu() */
38681da177e4SLinus Torvalds }
38691da177e4SLinus Torvalds 
38701da177e4SLinus Torvalds module_init(pg_init);
38711da177e4SLinus Torvalds module_exit(pg_cleanup);
38721da177e4SLinus Torvalds 
3873c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
38741da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool");
38751da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3876c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION);
38771da177e4SLinus Torvalds module_param(pg_count_d, int, 0);
3878c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
38791da177e4SLinus Torvalds module_param(pg_delay_d, int, 0);
3880c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
38811da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0);
3882c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
38831da177e4SLinus Torvalds module_param(debug, int, 0);
3884c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");
3885