xref: /openbmc/linux/net/core/pktgen.c (revision 3de03596dfeee48bc803c1d1a6daf60a459929f3)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Authors:
31da177e4SLinus Torvalds  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
41da177e4SLinus Torvalds  *                             Uppsala University and
51da177e4SLinus Torvalds  *                             Swedish University of Agricultural Sciences
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Alexey Kuznetsov  <kuznet@ms2.inr.ac.ru>
81da177e4SLinus Torvalds  * Ben Greear <greearb@candelatech.com>
996de0e25SJan Engelhardt  * Jens Låås <jens.laas@data.slu.se>
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
121da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
131da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
141da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * A tool for loading the network with preconfigurated packets.
181da177e4SLinus Torvalds  * The tool is implemented as a linux module.  Parameters are output
191da177e4SLinus Torvalds  * device, delay (to hard_xmit), number of packets, and whether
201da177e4SLinus Torvalds  * to use multiple SKBs or just the same one.
211da177e4SLinus Torvalds  * pktgen uses the installed interface's output routine.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * Additional hacking by:
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * Jens.Laas@data.slu.se
261da177e4SLinus Torvalds  * Improved by ANK. 010120.
271da177e4SLinus Torvalds  * Improved by ANK even more. 010212.
281da177e4SLinus Torvalds  * MAC address typo fixed. 010417 --ro
291da177e4SLinus Torvalds  * Integrated.  020301 --DaveM
301da177e4SLinus Torvalds  * Added multiskb option 020301 --DaveM
311da177e4SLinus Torvalds  * Scaling of results. 020417--sigurdur@linpro.no
321da177e4SLinus Torvalds  * Significant re-work of the module:
331da177e4SLinus Torvalds  *   *  Convert to threaded model to more efficiently be able to transmit
341da177e4SLinus Torvalds  *       and receive on multiple interfaces at once.
351da177e4SLinus Torvalds  *   *  Converted many counters to __u64 to allow longer runs.
361da177e4SLinus Torvalds  *   *  Allow configuration of ranges, like min/max IP address, MACs,
371da177e4SLinus Torvalds  *       and UDP-ports, for both source and destination, and can
381da177e4SLinus Torvalds  *       set to use a random distribution or sequentially walk the range.
391da177e4SLinus Torvalds  *   *  Can now change most values after starting.
401da177e4SLinus Torvalds  *   *  Place 12-byte packet in UDP payload with magic number,
411da177e4SLinus Torvalds  *       sequence number, and timestamp.
421da177e4SLinus Torvalds  *   *  Add receiver code that detects dropped pkts, re-ordered pkts, and
431da177e4SLinus Torvalds  *       latencies (with micro-second) precision.
441da177e4SLinus Torvalds  *   *  Add IOCTL interface to easily get counters & configuration.
451da177e4SLinus Torvalds  *   --Ben Greear <greearb@candelatech.com>
461da177e4SLinus Torvalds  *
471da177e4SLinus Torvalds  * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
481da177e4SLinus Torvalds  * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
491da177e4SLinus Torvalds  * as a "fastpath" with a configurable number of clones after alloc's.
501da177e4SLinus Torvalds  * clone_skb=0 means all packets are allocated this also means ranges time
511da177e4SLinus Torvalds  * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
521da177e4SLinus Torvalds  * clones.
531da177e4SLinus Torvalds  *
541da177e4SLinus Torvalds  * Also moved to /proc/net/pktgen/
551da177e4SLinus Torvalds  * --ro
561da177e4SLinus Torvalds  *
571da177e4SLinus Torvalds  * Sept 10:  Fixed threading/locking.  Lots of bone-headed and more clever
581da177e4SLinus Torvalds  *    mistakes.  Also merged in DaveM's patch in the -pre6 patch.
591da177e4SLinus Torvalds  * --Ben Greear <greearb@candelatech.com>
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  *
641da177e4SLinus Torvalds  * 021124 Finished major redesign and rewrite for new functionality.
651da177e4SLinus Torvalds  * See Documentation/networking/pktgen.txt for how to use this.
661da177e4SLinus Torvalds  *
671da177e4SLinus Torvalds  * The new operation:
681da177e4SLinus Torvalds  * For each CPU one thread/process is created at start. This process checks
691da177e4SLinus Torvalds  * for running devices in the if_list and sends packets until count is 0 it
701da177e4SLinus Torvalds  * also the thread checks the thread->control which is used for inter-process
711da177e4SLinus Torvalds  * communication. controlling process "posts" operations to the threads this
728788370aSJesper Dangaard Brouer  * way.
738788370aSJesper Dangaard Brouer  * The if_list is RCU protected, and the if_lock remains to protect updating
748788370aSJesper Dangaard Brouer  * of if_list, from "add_device" as it invoked from userspace (via proc write).
751da177e4SLinus Torvalds  *
761da177e4SLinus Torvalds  * By design there should only be *one* "controlling" process. In practice
771da177e4SLinus Torvalds  * multiple write accesses gives unpredictable result. Understood by "write"
781da177e4SLinus Torvalds  * to /proc gives result code thats should be read be the "writer".
79b4099fabSStephen Hemminger  * For practical use this should be no problem.
801da177e4SLinus Torvalds  *
811da177e4SLinus Torvalds  * Note when adding devices to a specific CPU there good idea to also assign
821da177e4SLinus Torvalds  * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU.
831da177e4SLinus Torvalds  * --ro
841da177e4SLinus Torvalds  *
851da177e4SLinus Torvalds  * Fix refcount off by one if first packet fails, potential null deref,
861da177e4SLinus Torvalds  * memleak 030710- KJP
871da177e4SLinus Torvalds  *
881da177e4SLinus Torvalds  * First "ranges" functionality for ipv6 030726 --ro
891da177e4SLinus Torvalds  *
901da177e4SLinus Torvalds  * Included flow support. 030802 ANK.
911da177e4SLinus Torvalds  *
921da177e4SLinus Torvalds  * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
931da177e4SLinus Torvalds  *
941da177e4SLinus Torvalds  * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
951da177e4SLinus Torvalds  * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
961da177e4SLinus Torvalds  *
971da177e4SLinus Torvalds  * New xmit() return, do_div and misc clean up by Stephen Hemminger
981da177e4SLinus Torvalds  * <shemminger@osdl.org> 040923
991da177e4SLinus Torvalds  *
100ca9f1fd2SStephen Hemminger  * Randy Dunlap fixed u64 printk compiler warning
1011da177e4SLinus Torvalds  *
1021da177e4SLinus Torvalds  * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
1031da177e4SLinus Torvalds  * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
1041da177e4SLinus Torvalds  *
1051da177e4SLinus Torvalds  * Corrections from Nikolai Malykh (nmalykh@bilim.com)
1061da177e4SLinus Torvalds  * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
1071da177e4SLinus Torvalds  *
1081da177e4SLinus Torvalds  * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
1091da177e4SLinus Torvalds  * 050103
110ca6549afSSteven Whitehouse  *
111ca6549afSSteven Whitehouse  * MPLS support by Steven Whitehouse <steve@chygwyn.com>
112ca6549afSSteven Whitehouse  *
11334954ddcSFrancesco Fondelli  * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
11434954ddcSFrancesco Fondelli  *
115ce5d0b47SAdit Ranadive  * Fixed src_mac command to set source mac of packet to value specified in
116ce5d0b47SAdit Ranadive  * command by Adit Ranadive <adit.262@gmail.com>
117ce5d0b47SAdit Ranadive  *
1181da177e4SLinus Torvalds  */
119f9467eaeSJoe Perches 
120f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
121f9467eaeSJoe Perches 
1221da177e4SLinus Torvalds #include <linux/sys.h>
1231da177e4SLinus Torvalds #include <linux/types.h>
1241da177e4SLinus Torvalds #include <linux/module.h>
1251da177e4SLinus Torvalds #include <linux/moduleparam.h>
1261da177e4SLinus Torvalds #include <linux/kernel.h>
127222fa076SLuiz Capitulino #include <linux/mutex.h>
1281da177e4SLinus Torvalds #include <linux/sched.h>
1291da177e4SLinus Torvalds #include <linux/slab.h>
1301da177e4SLinus Torvalds #include <linux/vmalloc.h>
1311da177e4SLinus Torvalds #include <linux/unistd.h>
1321da177e4SLinus Torvalds #include <linux/string.h>
1331da177e4SLinus Torvalds #include <linux/ptrace.h>
1341da177e4SLinus Torvalds #include <linux/errno.h>
1351da177e4SLinus Torvalds #include <linux/ioport.h>
1361da177e4SLinus Torvalds #include <linux/interrupt.h>
1374fc268d2SRandy Dunlap #include <linux/capability.h>
1382bc481cfSStephen Hemminger #include <linux/hrtimer.h>
13909fe3ef4SAndrew Morton #include <linux/freezer.h>
1401da177e4SLinus Torvalds #include <linux/delay.h>
1411da177e4SLinus Torvalds #include <linux/timer.h>
142cdcdbe0bSLuiz Capitulino #include <linux/list.h>
1431da177e4SLinus Torvalds #include <linux/init.h>
1441da177e4SLinus Torvalds #include <linux/skbuff.h>
1451da177e4SLinus Torvalds #include <linux/netdevice.h>
1461da177e4SLinus Torvalds #include <linux/inet.h>
1471da177e4SLinus Torvalds #include <linux/inetdevice.h>
1481da177e4SLinus Torvalds #include <linux/rtnetlink.h>
1491da177e4SLinus Torvalds #include <linux/if_arp.h>
15034954ddcSFrancesco Fondelli #include <linux/if_vlan.h>
1511da177e4SLinus Torvalds #include <linux/in.h>
1521da177e4SLinus Torvalds #include <linux/ip.h>
1531da177e4SLinus Torvalds #include <linux/ipv6.h>
1541da177e4SLinus Torvalds #include <linux/udp.h>
1551da177e4SLinus Torvalds #include <linux/proc_fs.h>
156d50a6b56SStephen Hemminger #include <linux/seq_file.h>
1571da177e4SLinus Torvalds #include <linux/wait.h>
158f404e9a6SKris Katterjohn #include <linux/etherdevice.h>
159ee74baa7SDavid S. Miller #include <linux/kthread.h>
160268bb0ceSLinus Torvalds #include <linux/prefetch.h>
161457c4cbcSEric W. Biederman #include <net/net_namespace.h>
1621da177e4SLinus Torvalds #include <net/checksum.h>
1631da177e4SLinus Torvalds #include <net/ipv6.h>
164c26bf4a5SThomas Graf #include <net/udp.h>
16573d94e94SStephen Rothwell #include <net/ip6_checksum.h>
1661da177e4SLinus Torvalds #include <net/addrconf.h>
167a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
168a553e4a6SJamal Hadi Salim #include <net/xfrm.h>
169a553e4a6SJamal Hadi Salim #endif
1704e58a027SCong Wang #include <net/netns/generic.h>
1711da177e4SLinus Torvalds #include <asm/byteorder.h>
1721da177e4SLinus Torvalds #include <linux/rcupdate.h>
1731977f032SJiri Slaby #include <linux/bitops.h>
17463adc6fbSStephen Hemminger #include <linux/io.h>
17563adc6fbSStephen Hemminger #include <linux/timex.h>
17663adc6fbSStephen Hemminger #include <linux/uaccess.h>
1771da177e4SLinus Torvalds #include <asm/dma.h>
1781da177e4SLinus Torvalds #include <asm/div64.h>		/* do_div */
1791da177e4SLinus Torvalds 
18040207264SJesper Dangaard Brouer #define VERSION	"2.75"
1811da177e4SLinus Torvalds #define IP_NAME_SZ 32
182ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
183d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100)
1841da177e4SLinus Torvalds 
185f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__);
186f9467eaeSJoe Perches 
1871da177e4SLinus Torvalds /* Device flag bits */
1881da177e4SLinus Torvalds #define F_IPSRC_RND   (1<<0)	/* IP-Src Random  */
1891da177e4SLinus Torvalds #define F_IPDST_RND   (1<<1)	/* IP-Dst Random  */
1901da177e4SLinus Torvalds #define F_UDPSRC_RND  (1<<2)	/* UDP-Src Random */
1911da177e4SLinus Torvalds #define F_UDPDST_RND  (1<<3)	/* UDP-Dst Random */
1921da177e4SLinus Torvalds #define F_MACSRC_RND  (1<<4)	/* MAC-Src Random */
1931da177e4SLinus Torvalds #define F_MACDST_RND  (1<<5)	/* MAC-Dst Random */
1941da177e4SLinus Torvalds #define F_TXSIZE_RND  (1<<6)	/* Transmit size is random */
1951da177e4SLinus Torvalds #define F_IPV6        (1<<7)	/* Interface in IPV6 Mode */
196ca6549afSSteven Whitehouse #define F_MPLS_RND    (1<<8)	/* Random MPLS labels */
19734954ddcSFrancesco Fondelli #define F_VID_RND     (1<<9)	/* Random VLAN ID */
19834954ddcSFrancesco Fondelli #define F_SVID_RND    (1<<10)	/* Random SVLAN ID */
199007a531bSJamal Hadi Salim #define F_FLOW_SEQ    (1<<11)	/* Sequential flows */
200a553e4a6SJamal Hadi Salim #define F_IPSEC_ON    (1<<12)	/* ipsec on for flows */
20145b270f8SRobert Olsson #define F_QUEUE_MAP_RND (1<<13)	/* queue map Random */
202e6fce5b9SRobert Olsson #define F_QUEUE_MAP_CPU (1<<14)	/* queue map mirrors smp_processor_id() */
203e99b99b4SRobert Olsson #define F_NODE          (1<<15)	/* Node memory alloc*/
204c26bf4a5SThomas Graf #define F_UDPCSUM       (1<<16)	/* Include UDP checksum */
205afb84b62SJesper Dangaard Brouer #define F_NO_TIMESTAMP  (1<<17)	/* Don't timestamp packets (default TS) */
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds /* Thread control flag bits */
2086b80d6a6SStephen Hemminger #define T_STOP        (1<<0)	/* Stop run */
2096b80d6a6SStephen Hemminger #define T_RUN         (1<<1)	/* Start run */
2106b80d6a6SStephen Hemminger #define T_REMDEVALL   (1<<2)	/* Remove all devs */
2116b80d6a6SStephen Hemminger #define T_REMDEV      (1<<3)	/* Remove one dev */
2121da177e4SLinus Torvalds 
21362f64aedSAlexei Starovoitov /* Xmit modes */
21462f64aedSAlexei Starovoitov #define M_START_XMIT		0	/* Default normal TX */
21562f64aedSAlexei Starovoitov #define M_NETIF_RECEIVE 	1	/* Inject packets into stack */
21662f64aedSAlexei Starovoitov 
2178788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */
2181da177e4SLinus Torvalds #define   if_lock(t)           spin_lock(&(t->if_lock));
2191da177e4SLinus Torvalds #define   if_unlock(t)           spin_unlock(&(t->if_lock));
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */
2221da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955
223d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen"
224d50a6b56SStephen Hemminger #define PGCTRL	    "pgctrl"
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds #define MAX_CFLOWS  65536
2271da177e4SLinus Torvalds 
22834954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
22934954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
23034954ddcSFrancesco Fondelli 
231222f1806SLuiz Capitulino struct flow_state {
232252e3346SAl Viro 	__be32 cur_daddr;
2331da177e4SLinus Torvalds 	int count;
234a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
235a553e4a6SJamal Hadi Salim 	struct xfrm_state *x;
236a553e4a6SJamal Hadi Salim #endif
237007a531bSJamal Hadi Salim 	__u32 flags;
2381da177e4SLinus Torvalds };
2391da177e4SLinus Torvalds 
240007a531bSJamal Hadi Salim /* flow flag bits */
241007a531bSJamal Hadi Salim #define F_INIT   (1<<0)		/* flow has been initialized */
242007a531bSJamal Hadi Salim 
2431da177e4SLinus Torvalds struct pktgen_dev {
2441da177e4SLinus Torvalds 	/*
2451da177e4SLinus Torvalds 	 * Try to keep frequent/infrequent used vars. separated.
2461da177e4SLinus Torvalds 	 */
24739df232fSStephen Hemminger 	struct proc_dir_entry *entry;	/* proc file */
2481da177e4SLinus Torvalds 	struct pktgen_thread *pg_thread;/* the owner */
24963adc6fbSStephen Hemminger 	struct list_head list;		/* chaining in the thread's run-queue */
2508788370aSJesper Dangaard Brouer 	struct rcu_head	 rcu;		/* freed by RCU */
2511da177e4SLinus Torvalds 
25263adc6fbSStephen Hemminger 	int running;		/* if false, the test will stop */
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	/* If min != max, then we will either do a linear iteration, or
2551da177e4SLinus Torvalds 	 * we will do a random selection from within the range.
2561da177e4SLinus Torvalds 	 */
2571da177e4SLinus Torvalds 	__u32 flags;
25862f64aedSAlexei Starovoitov 	int xmit_mode;
25968bf9f0bSAmerigo Wang 	int min_pkt_size;
26068bf9f0bSAmerigo Wang 	int max_pkt_size;
26116dab72fSJamal Hadi Salim 	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
2621da177e4SLinus Torvalds 	int nfrags;
26362f64aedSAlexei Starovoitov 	int removal_mark;	/* non-zero => the device is marked for
26462f64aedSAlexei Starovoitov 				 * removal by worker thread */
26562f64aedSAlexei Starovoitov 
26626ad7879SEric Dumazet 	struct page *page;
267fd29cf72SStephen Hemminger 	u64 delay;		/* nano-seconds */
268fd29cf72SStephen Hemminger 
2691da177e4SLinus Torvalds 	__u64 count;		/* Default No packets to send */
2701da177e4SLinus Torvalds 	__u64 sofar;		/* How many pkts we've sent so far */
2711da177e4SLinus Torvalds 	__u64 tx_bytes;		/* How many bytes we've transmitted */
272f466dba1SJohn Fastabend 	__u64 errors;		/* Errors when trying to transmit, */
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	/* runtime counters relating to clone_skb */
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	__u32 clone_count;
2771da177e4SLinus Torvalds 	int last_ok;		/* Was last skb sent?
27863adc6fbSStephen Hemminger 				 * Or a failed transmit of some sort?
27963adc6fbSStephen Hemminger 				 * This will keep sequence numbers in order
2801da177e4SLinus Torvalds 				 */
281fd29cf72SStephen Hemminger 	ktime_t next_tx;
282fd29cf72SStephen Hemminger 	ktime_t started_at;
283fd29cf72SStephen Hemminger 	ktime_t stopped_at;
284fd29cf72SStephen Hemminger 	u64	idle_acc;	/* nano-seconds */
285fd29cf72SStephen Hemminger 
2861da177e4SLinus Torvalds 	__u32 seq_num;
2871da177e4SLinus Torvalds 
28863adc6fbSStephen Hemminger 	int clone_skb;		/*
28963adc6fbSStephen Hemminger 				 * Use multiple SKBs during packet gen.
29063adc6fbSStephen Hemminger 				 * If this number is greater than 1, then
29163adc6fbSStephen Hemminger 				 * that many copies of the same packet will be
29263adc6fbSStephen Hemminger 				 * sent before a new packet is allocated.
29363adc6fbSStephen Hemminger 				 * If you want to send 1024 identical packets
29463adc6fbSStephen Hemminger 				 * before creating a new packet,
29563adc6fbSStephen Hemminger 				 * set clone_skb to 1024.
2961da177e4SLinus Torvalds 				 */
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	char dst_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
2991da177e4SLinus Torvalds 	char dst_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3001da177e4SLinus Torvalds 	char src_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3011da177e4SLinus Torvalds 	char src_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	struct in6_addr in6_saddr;
3041da177e4SLinus Torvalds 	struct in6_addr in6_daddr;
3051da177e4SLinus Torvalds 	struct in6_addr cur_in6_daddr;
3061da177e4SLinus Torvalds 	struct in6_addr cur_in6_saddr;
3071da177e4SLinus Torvalds 	/* For ranges */
3081da177e4SLinus Torvalds 	struct in6_addr min_in6_daddr;
3091da177e4SLinus Torvalds 	struct in6_addr max_in6_daddr;
3101da177e4SLinus Torvalds 	struct in6_addr min_in6_saddr;
3111da177e4SLinus Torvalds 	struct in6_addr max_in6_saddr;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	/* If we're doing ranges, random or incremental, then this
3141da177e4SLinus Torvalds 	 * defines the min/max for those ranges.
3151da177e4SLinus Torvalds 	 */
316252e3346SAl Viro 	__be32 saddr_min;	/* inclusive, source IP address */
317252e3346SAl Viro 	__be32 saddr_max;	/* exclusive, source IP address */
318252e3346SAl Viro 	__be32 daddr_min;	/* inclusive, dest IP address */
319252e3346SAl Viro 	__be32 daddr_max;	/* exclusive, dest IP address */
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	__u16 udp_src_min;	/* inclusive, source UDP port */
3221da177e4SLinus Torvalds 	__u16 udp_src_max;	/* exclusive, source UDP port */
3231da177e4SLinus Torvalds 	__u16 udp_dst_min;	/* inclusive, dest UDP port */
3241da177e4SLinus Torvalds 	__u16 udp_dst_max;	/* exclusive, dest UDP port */
3251da177e4SLinus Torvalds 
3261ca7768cSFrancesco Fondelli 	/* DSCP + ECN */
32763adc6fbSStephen Hemminger 	__u8 tos;            /* six MSB of (former) IPv4 TOS
32863adc6fbSStephen Hemminger 				are for dscp codepoint */
32963adc6fbSStephen Hemminger 	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6
33063adc6fbSStephen Hemminger 				(see RFC 3260, sec. 4) */
3311ca7768cSFrancesco Fondelli 
332ca6549afSSteven Whitehouse 	/* MPLS */
33395c96174SEric Dumazet 	unsigned int nr_labels;	/* Depth of stack, 0 = no MPLS */
334ca6549afSSteven Whitehouse 	__be32 labels[MAX_MPLS_LABELS];
335ca6549afSSteven Whitehouse 
33634954ddcSFrancesco Fondelli 	/* VLAN/SVLAN (802.1Q/Q-in-Q) */
33734954ddcSFrancesco Fondelli 	__u8  vlan_p;
33834954ddcSFrancesco Fondelli 	__u8  vlan_cfi;
33934954ddcSFrancesco Fondelli 	__u16 vlan_id;  /* 0xffff means no vlan tag */
34034954ddcSFrancesco Fondelli 
34134954ddcSFrancesco Fondelli 	__u8  svlan_p;
34234954ddcSFrancesco Fondelli 	__u8  svlan_cfi;
34334954ddcSFrancesco Fondelli 	__u16 svlan_id; /* 0xffff means no svlan tag */
34434954ddcSFrancesco Fondelli 
3451da177e4SLinus Torvalds 	__u32 src_mac_count;	/* How many MACs to iterate through */
3461da177e4SLinus Torvalds 	__u32 dst_mac_count;	/* How many MACs to iterate through */
3471da177e4SLinus Torvalds 
348f404e9a6SKris Katterjohn 	unsigned char dst_mac[ETH_ALEN];
349f404e9a6SKris Katterjohn 	unsigned char src_mac[ETH_ALEN];
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	__u32 cur_dst_mac_offset;
3521da177e4SLinus Torvalds 	__u32 cur_src_mac_offset;
353252e3346SAl Viro 	__be32 cur_saddr;
354252e3346SAl Viro 	__be32 cur_daddr;
35566ed1e5eSEric Dumazet 	__u16 ip_id;
3561da177e4SLinus Torvalds 	__u16 cur_udp_dst;
3571da177e4SLinus Torvalds 	__u16 cur_udp_src;
35845b270f8SRobert Olsson 	__u16 cur_queue_map;
3591da177e4SLinus Torvalds 	__u32 cur_pkt_size;
360baac8564SEric Dumazet 	__u32 last_pkt_size;
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 	__u8 hh[14];
3631da177e4SLinus Torvalds 	/* = {
3641da177e4SLinus Torvalds 	   0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	   We fill in SRC address later
3671da177e4SLinus Torvalds 	   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3681da177e4SLinus Torvalds 	   0x08, 0x00
3691da177e4SLinus Torvalds 	   };
3701da177e4SLinus Torvalds 	 */
3711da177e4SLinus Torvalds 	__u16 pad;		/* pad out the hh struct to an even 16 bytes */
3721da177e4SLinus Torvalds 
37363adc6fbSStephen Hemminger 	struct sk_buff *skb;	/* skb we are to transmit next, used for when we
3741da177e4SLinus Torvalds 				 * are transmitting the same one multiple times
3751da177e4SLinus Torvalds 				 */
37663adc6fbSStephen Hemminger 	struct net_device *odev; /* The out-going device.
37763adc6fbSStephen Hemminger 				  * Note that the device should have it's
37863adc6fbSStephen Hemminger 				  * pg_info pointer pointing back to this
37963adc6fbSStephen Hemminger 				  * device.
38063adc6fbSStephen Hemminger 				  * Set when the user specifies the out-going
38163adc6fbSStephen Hemminger 				  * device name (not when the inject is
3821da177e4SLinus Torvalds 				  * started as it used to do.)
3831da177e4SLinus Torvalds 				  */
384593f63b0SEric Dumazet 	char odevname[32];
3851da177e4SLinus Torvalds 	struct flow_state *flows;
38695c96174SEric Dumazet 	unsigned int cflows;	/* Concurrent flows (config) */
38795c96174SEric Dumazet 	unsigned int lflow;		/* Flow length  (config) */
38895c96174SEric Dumazet 	unsigned int nflows;	/* accumulated flows (stats) */
38995c96174SEric Dumazet 	unsigned int curfl;		/* current sequenced flow (state)*/
39045b270f8SRobert Olsson 
39145b270f8SRobert Olsson 	u16 queue_map_min;
39245b270f8SRobert Olsson 	u16 queue_map_max;
3939e50e3acSJohn Fastabend 	__u32 skb_priority;	/* skb priority field */
39438b2cf29SAlexei Starovoitov 	unsigned int burst;	/* number of duplicated packets to burst */
395e99b99b4SRobert Olsson 	int node;               /* Memory node */
39645b270f8SRobert Olsson 
397a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
398a553e4a6SJamal Hadi Salim 	__u8	ipsmode;		/* IPSEC mode (config) */
399a553e4a6SJamal Hadi Salim 	__u8	ipsproto;		/* IPSEC type (config) */
400de4aee7dSFan Du 	__u32	spi;
401cf93d47eSFan Du 	struct dst_entry dst;
402cf93d47eSFan Du 	struct dst_ops dstops;
403a553e4a6SJamal Hadi Salim #endif
40439df232fSStephen Hemminger 	char result[512];
4051da177e4SLinus Torvalds };
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds struct pktgen_hdr {
408252e3346SAl Viro 	__be32 pgh_magic;
409252e3346SAl Viro 	__be32 seq_num;
410252e3346SAl Viro 	__be32 tv_sec;
411252e3346SAl Viro 	__be32 tv_usec;
4121da177e4SLinus Torvalds };
4131da177e4SLinus Torvalds 
4144e58a027SCong Wang 
4154e58a027SCong Wang static int pg_net_id __read_mostly;
4164e58a027SCong Wang 
4174e58a027SCong Wang struct pktgen_net {
4184e58a027SCong Wang 	struct net		*net;
4194e58a027SCong Wang 	struct proc_dir_entry	*proc_dir;
4204e58a027SCong Wang 	struct list_head	pktgen_threads;
4214e58a027SCong Wang 	bool			pktgen_exiting;
4224e58a027SCong Wang };
423551eaff1SEric Dumazet 
4241da177e4SLinus Torvalds struct pktgen_thread {
42563adc6fbSStephen Hemminger 	spinlock_t if_lock;		/* for list of devices */
426c26a8016SLuiz Capitulino 	struct list_head if_list;	/* All device here */
427cdcdbe0bSLuiz Capitulino 	struct list_head th_list;
428ee74baa7SDavid S. Miller 	struct task_struct *tsk;
4291da177e4SLinus Torvalds 	char result[512];
4301da177e4SLinus Torvalds 
43163adc6fbSStephen Hemminger 	/* Field for thread to receive "posted" events terminate,
43263adc6fbSStephen Hemminger 	   stop ifs etc. */
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	u32 control;
4351da177e4SLinus Torvalds 	int cpu;
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 	wait_queue_head_t queue;
438d3ede327SDenis V. Lunev 	struct completion start_done;
4394e58a027SCong Wang 	struct pktgen_net *net;
4401da177e4SLinus Torvalds };
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds #define REMOVE 1
4431da177e4SLinus Torvalds #define FIND   0
4441da177e4SLinus Torvalds 
445c3d2f52dSStephen Hemminger static const char version[] =
446f9467eaeSJoe Perches 	"Packet Generator for packet performance testing. "
447f9467eaeSJoe Perches 	"Version: " VERSION "\n";
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
4501da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
451222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
4523e984840SEric Dumazet 					  const char *ifname, bool exact);
4531da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
4544e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn);
4554e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn);
4564e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn);
4573bda06a3SStephen Hemminger 
4581da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t);
4591da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
46039df232fSStephen Hemminger 
4611da177e4SLinus Torvalds /* Module parameters, defaults. */
46265c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000;
46365c5b786SStephen Hemminger static int pg_delay_d __read_mostly;
46465c5b786SStephen Hemminger static int pg_clone_skb_d  __read_mostly;
46565c5b786SStephen Hemminger static int debug  __read_mostly;
4661da177e4SLinus Torvalds 
467222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock);
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = {
4701da177e4SLinus Torvalds 	.notifier_call = pktgen_device_event,
4711da177e4SLinus Torvalds };
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds /*
4741da177e4SLinus Torvalds  * /proc handling functions
4751da177e4SLinus Torvalds  *
4761da177e4SLinus Torvalds  */
4771da177e4SLinus Torvalds 
478d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v)
479d50a6b56SStephen Hemminger {
480c3d2f52dSStephen Hemminger 	seq_puts(seq, version);
481d50a6b56SStephen Hemminger 	return 0;
482d50a6b56SStephen Hemminger }
4831da177e4SLinus Torvalds 
484d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf,
4851da177e4SLinus Torvalds 			    size_t count, loff_t *ppos)
4861da177e4SLinus Torvalds {
487d50a6b56SStephen Hemminger 	char data[128];
4884e58a027SCong Wang 	struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
4891da177e4SLinus Torvalds 
49009455747SMathias Krause 	if (!capable(CAP_NET_ADMIN))
49109455747SMathias Krause 		return -EPERM;
4921da177e4SLinus Torvalds 
49320b0c718SMathias Krause 	if (count == 0)
49420b0c718SMathias Krause 		return -EINVAL;
49520b0c718SMathias Krause 
496d50a6b56SStephen Hemminger 	if (count > sizeof(data))
497d50a6b56SStephen Hemminger 		count = sizeof(data);
4981da177e4SLinus Torvalds 
49909455747SMathias Krause 	if (copy_from_user(data, buf, count))
50009455747SMathias Krause 		return -EFAULT;
50109455747SMathias Krause 
50220b0c718SMathias Krause 	data[count - 1] = 0;	/* Strip trailing '\n' and terminate string */
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds 	if (!strcmp(data, "stop"))
5054e58a027SCong Wang 		pktgen_stop_all_threads_ifs(pn);
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	else if (!strcmp(data, "start"))
5084e58a027SCong Wang 		pktgen_run_all_threads(pn);
5091da177e4SLinus Torvalds 
510eb37b41cSJesse Brandeburg 	else if (!strcmp(data, "reset"))
5114e58a027SCong Wang 		pktgen_reset_all_threads(pn);
512eb37b41cSJesse Brandeburg 
5131da177e4SLinus Torvalds 	else
51440207264SJesper Dangaard Brouer 		return -EINVAL;
5151da177e4SLinus Torvalds 
51609455747SMathias Krause 	return count;
5171da177e4SLinus Torvalds }
5181da177e4SLinus Torvalds 
519d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file)
5201da177e4SLinus Torvalds {
521d9dda78bSAl Viro 	return single_open(file, pgctrl_show, PDE_DATA(inode));
522d50a6b56SStephen Hemminger }
523d50a6b56SStephen Hemminger 
5249a32144eSArjan van de Ven static const struct file_operations pktgen_fops = {
525d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
526d50a6b56SStephen Hemminger 	.open    = pgctrl_open,
527d50a6b56SStephen Hemminger 	.read    = seq_read,
528d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
529d50a6b56SStephen Hemminger 	.write   = pgctrl_write,
530d50a6b56SStephen Hemminger 	.release = single_release,
531d50a6b56SStephen Hemminger };
532d50a6b56SStephen Hemminger 
533d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v)
534d50a6b56SStephen Hemminger {
535648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev = seq->private;
536fd29cf72SStephen Hemminger 	ktime_t stopped;
537fd29cf72SStephen Hemminger 	u64 idle;
5381da177e4SLinus Torvalds 
539222f1806SLuiz Capitulino 	seq_printf(seq,
540222f1806SLuiz Capitulino 		   "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
541222f1806SLuiz Capitulino 		   (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size,
542222f1806SLuiz Capitulino 		   pkt_dev->max_pkt_size);
5431da177e4SLinus Torvalds 
544222f1806SLuiz Capitulino 	seq_printf(seq,
545fd29cf72SStephen Hemminger 		   "     frags: %d  delay: %llu  clone_skb: %d  ifname: %s\n",
546fd29cf72SStephen Hemminger 		   pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
547593f63b0SEric Dumazet 		   pkt_dev->clone_skb, pkt_dev->odevname);
5481da177e4SLinus Torvalds 
549222f1806SLuiz Capitulino 	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
550222f1806SLuiz Capitulino 		   pkt_dev->lflow);
5511da177e4SLinus Torvalds 
55245b270f8SRobert Olsson 	seq_printf(seq,
55345b270f8SRobert Olsson 		   "     queue_map_min: %u  queue_map_max: %u\n",
55445b270f8SRobert Olsson 		   pkt_dev->queue_map_min,
55545b270f8SRobert Olsson 		   pkt_dev->queue_map_max);
55645b270f8SRobert Olsson 
5579e50e3acSJohn Fastabend 	if (pkt_dev->skb_priority)
5589e50e3acSJohn Fastabend 		seq_printf(seq, "     skb_priority: %u\n",
5599e50e3acSJohn Fastabend 			   pkt_dev->skb_priority);
5609e50e3acSJohn Fastabend 
5611da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
562222f1806SLuiz Capitulino 		seq_printf(seq,
56347a0200dSAlexey Dobriyan 			   "     saddr: %pI6c  min_saddr: %pI6c  max_saddr: %pI6c\n"
56447a0200dSAlexey Dobriyan 			   "     daddr: %pI6c  min_daddr: %pI6c  max_daddr: %pI6c\n",
56547a0200dSAlexey Dobriyan 			   &pkt_dev->in6_saddr,
56647a0200dSAlexey Dobriyan 			   &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr,
56747a0200dSAlexey Dobriyan 			   &pkt_dev->in6_daddr,
56847a0200dSAlexey Dobriyan 			   &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr);
56963adc6fbSStephen Hemminger 	} else {
570222f1806SLuiz Capitulino 		seq_printf(seq,
57163adc6fbSStephen Hemminger 			   "     dst_min: %s  dst_max: %s\n",
57263adc6fbSStephen Hemminger 			   pkt_dev->dst_min, pkt_dev->dst_max);
57363adc6fbSStephen Hemminger 		seq_printf(seq,
57463adc6fbSStephen Hemminger 			   "     src_min: %s  src_max: %s\n",
57563adc6fbSStephen Hemminger 			   pkt_dev->src_min, pkt_dev->src_max);
57663adc6fbSStephen Hemminger 	}
5771da177e4SLinus Torvalds 
578d50a6b56SStephen Hemminger 	seq_puts(seq, "     src_mac: ");
5791da177e4SLinus Torvalds 
580e174961cSJohannes Berg 	seq_printf(seq, "%pM ",
581e174961cSJohannes Berg 		   is_zero_ether_addr(pkt_dev->src_mac) ?
582e174961cSJohannes Berg 			     pkt_dev->odev->dev_addr : pkt_dev->src_mac);
5831da177e4SLinus Torvalds 
58497dc48e2SThomas Graf 	seq_puts(seq, "dst_mac: ");
585e174961cSJohannes Berg 	seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
5861da177e4SLinus Torvalds 
587222f1806SLuiz Capitulino 	seq_printf(seq,
58863adc6fbSStephen Hemminger 		   "     udp_src_min: %d  udp_src_max: %d"
58963adc6fbSStephen Hemminger 		   "  udp_dst_min: %d  udp_dst_max: %d\n",
590222f1806SLuiz Capitulino 		   pkt_dev->udp_src_min, pkt_dev->udp_src_max,
591222f1806SLuiz Capitulino 		   pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);
5921da177e4SLinus Torvalds 
593222f1806SLuiz Capitulino 	seq_printf(seq,
594ca6549afSSteven Whitehouse 		   "     src_mac_count: %d  dst_mac_count: %d\n",
5951da177e4SLinus Torvalds 		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
5961da177e4SLinus Torvalds 
597ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels) {
59895c96174SEric Dumazet 		unsigned int i;
59997dc48e2SThomas Graf 		seq_puts(seq, "     mpls: ");
600ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
601ca6549afSSteven Whitehouse 			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
602ca6549afSSteven Whitehouse 				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
603ca6549afSSteven Whitehouse 	}
604ca6549afSSteven Whitehouse 
60563adc6fbSStephen Hemminger 	if (pkt_dev->vlan_id != 0xffff)
60634954ddcSFrancesco Fondelli 		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
60763adc6fbSStephen Hemminger 			   pkt_dev->vlan_id, pkt_dev->vlan_p,
60863adc6fbSStephen Hemminger 			   pkt_dev->vlan_cfi);
60934954ddcSFrancesco Fondelli 
61063adc6fbSStephen Hemminger 	if (pkt_dev->svlan_id != 0xffff)
61134954ddcSFrancesco Fondelli 		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
61263adc6fbSStephen Hemminger 			   pkt_dev->svlan_id, pkt_dev->svlan_p,
61363adc6fbSStephen Hemminger 			   pkt_dev->svlan_cfi);
61434954ddcSFrancesco Fondelli 
61563adc6fbSStephen Hemminger 	if (pkt_dev->tos)
6161ca7768cSFrancesco Fondelli 		seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);
6171ca7768cSFrancesco Fondelli 
61863adc6fbSStephen Hemminger 	if (pkt_dev->traffic_class)
6191ca7768cSFrancesco Fondelli 		seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
6201ca7768cSFrancesco Fondelli 
62138b2cf29SAlexei Starovoitov 	if (pkt_dev->burst > 1)
62238b2cf29SAlexei Starovoitov 		seq_printf(seq, "     burst: %d\n", pkt_dev->burst);
62338b2cf29SAlexei Starovoitov 
624e99b99b4SRobert Olsson 	if (pkt_dev->node >= 0)
625e99b99b4SRobert Olsson 		seq_printf(seq, "     node: %d\n", pkt_dev->node);
626e99b99b4SRobert Olsson 
62762f64aedSAlexei Starovoitov 	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
62862f64aedSAlexei Starovoitov 		seq_puts(seq, "     xmit_mode: netif_receive\n");
62962f64aedSAlexei Starovoitov 
63097dc48e2SThomas Graf 	seq_puts(seq, "     Flags: ");
631ca6549afSSteven Whitehouse 
6321da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
63397dc48e2SThomas Graf 		seq_puts(seq, "IPV6  ");
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPSRC_RND)
63697dc48e2SThomas Graf 		seq_puts(seq, "IPSRC_RND  ");
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPDST_RND)
63997dc48e2SThomas Graf 		seq_puts(seq, "IPDST_RND  ");
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	if (pkt_dev->flags & F_TXSIZE_RND)
64297dc48e2SThomas Graf 		seq_puts(seq, "TXSIZE_RND  ");
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds 	if (pkt_dev->flags & F_UDPSRC_RND)
64597dc48e2SThomas Graf 		seq_puts(seq, "UDPSRC_RND  ");
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 	if (pkt_dev->flags & F_UDPDST_RND)
64897dc48e2SThomas Graf 		seq_puts(seq, "UDPDST_RND  ");
6491da177e4SLinus Torvalds 
650c26bf4a5SThomas Graf 	if (pkt_dev->flags & F_UDPCSUM)
65197dc48e2SThomas Graf 		seq_puts(seq, "UDPCSUM  ");
652c26bf4a5SThomas Graf 
653afb84b62SJesper Dangaard Brouer 	if (pkt_dev->flags & F_NO_TIMESTAMP)
654afb84b62SJesper Dangaard Brouer 		seq_puts(seq, "NO_TIMESTAMP  ");
655afb84b62SJesper Dangaard Brouer 
656ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND)
65797dc48e2SThomas Graf 		seq_puts(seq,  "MPLS_RND  ");
658ca6549afSSteven Whitehouse 
65945b270f8SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_RND)
66097dc48e2SThomas Graf 		seq_puts(seq,  "QUEUE_MAP_RND  ");
66145b270f8SRobert Olsson 
662e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
66397dc48e2SThomas Graf 		seq_puts(seq,  "QUEUE_MAP_CPU  ");
664e6fce5b9SRobert Olsson 
665007a531bSJamal Hadi Salim 	if (pkt_dev->cflows) {
666007a531bSJamal Hadi Salim 		if (pkt_dev->flags & F_FLOW_SEQ)
66797dc48e2SThomas Graf 			seq_puts(seq,  "FLOW_SEQ  "); /*in sequence flows*/
668007a531bSJamal Hadi Salim 		else
66997dc48e2SThomas Graf 			seq_puts(seq,  "FLOW_RND  ");
670007a531bSJamal Hadi Salim 	}
671007a531bSJamal Hadi Salim 
672a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
6738101328bSFan Du 	if (pkt_dev->flags & F_IPSEC_ON) {
67497dc48e2SThomas Graf 		seq_puts(seq,  "IPSEC  ");
6758101328bSFan Du 		if (pkt_dev->spi)
6768101328bSFan Du 			seq_printf(seq, "spi:%u", pkt_dev->spi);
6778101328bSFan Du 	}
678a553e4a6SJamal Hadi Salim #endif
679a553e4a6SJamal Hadi Salim 
6801da177e4SLinus Torvalds 	if (pkt_dev->flags & F_MACSRC_RND)
68197dc48e2SThomas Graf 		seq_puts(seq, "MACSRC_RND  ");
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	if (pkt_dev->flags & F_MACDST_RND)
68497dc48e2SThomas Graf 		seq_puts(seq, "MACDST_RND  ");
6851da177e4SLinus Torvalds 
68634954ddcSFrancesco Fondelli 	if (pkt_dev->flags & F_VID_RND)
68797dc48e2SThomas Graf 		seq_puts(seq, "VID_RND  ");
68834954ddcSFrancesco Fondelli 
68934954ddcSFrancesco Fondelli 	if (pkt_dev->flags & F_SVID_RND)
69097dc48e2SThomas Graf 		seq_puts(seq, "SVID_RND  ");
69134954ddcSFrancesco Fondelli 
692e99b99b4SRobert Olsson 	if (pkt_dev->flags & F_NODE)
69397dc48e2SThomas Graf 		seq_puts(seq, "NODE_ALLOC  ");
694e99b99b4SRobert Olsson 
695d50a6b56SStephen Hemminger 	seq_puts(seq, "\n");
6961da177e4SLinus Torvalds 
697fd29cf72SStephen Hemminger 	/* not really stopped, more like last-running-at */
698398f382cSDaniel Borkmann 	stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at;
699fd29cf72SStephen Hemminger 	idle = pkt_dev->idle_acc;
700fd29cf72SStephen Hemminger 	do_div(idle, NSEC_PER_USEC);
7011da177e4SLinus Torvalds 
702222f1806SLuiz Capitulino 	seq_printf(seq,
703fd29cf72SStephen Hemminger 		   "Current:\n     pkts-sofar: %llu  errors: %llu\n",
7041da177e4SLinus Torvalds 		   (unsigned long long)pkt_dev->sofar,
705fd29cf72SStephen Hemminger 		   (unsigned long long)pkt_dev->errors);
706fd29cf72SStephen Hemminger 
707fd29cf72SStephen Hemminger 	seq_printf(seq,
708fd29cf72SStephen Hemminger 		   "     started: %lluus  stopped: %lluus idle: %lluus\n",
709fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(pkt_dev->started_at),
710fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(stopped),
711fd29cf72SStephen Hemminger 		   (unsigned long long) idle);
7121da177e4SLinus Torvalds 
713222f1806SLuiz Capitulino 	seq_printf(seq,
714222f1806SLuiz Capitulino 		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
715d50a6b56SStephen Hemminger 		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
716d50a6b56SStephen Hemminger 		   pkt_dev->cur_src_mac_offset);
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
71947a0200dSAlexey Dobriyan 		seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
72047a0200dSAlexey Dobriyan 				&pkt_dev->cur_in6_saddr,
72147a0200dSAlexey Dobriyan 				&pkt_dev->cur_in6_daddr);
722222f1806SLuiz Capitulino 	} else
7230373a946SAmerigo Wang 		seq_printf(seq, "     cur_saddr: %pI4  cur_daddr: %pI4\n",
7240373a946SAmerigo Wang 			   &pkt_dev->cur_saddr, &pkt_dev->cur_daddr);
7251da177e4SLinus Torvalds 
726d50a6b56SStephen Hemminger 	seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
7271da177e4SLinus Torvalds 		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
7281da177e4SLinus Torvalds 
72945b270f8SRobert Olsson 	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);
73045b270f8SRobert Olsson 
731d50a6b56SStephen Hemminger 	seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 	if (pkt_dev->result[0])
734d50a6b56SStephen Hemminger 		seq_printf(seq, "Result: %s\n", pkt_dev->result);
7351da177e4SLinus Torvalds 	else
73697dc48e2SThomas Graf 		seq_puts(seq, "Result: Idle\n");
7371da177e4SLinus Torvalds 
738d50a6b56SStephen Hemminger 	return 0;
7391da177e4SLinus Torvalds }
7401da177e4SLinus Torvalds 
741ca6549afSSteven Whitehouse 
74263adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
74363adc6fbSStephen Hemminger 		     __u32 *num)
744ca6549afSSteven Whitehouse {
745ca6549afSSteven Whitehouse 	int i = 0;
746ca6549afSSteven Whitehouse 	*num = 0;
747ca6549afSSteven Whitehouse 
7481ca7768cSFrancesco Fondelli 	for (; i < maxlen; i++) {
74982fd5b5dSAndy Shevchenko 		int value;
750ca6549afSSteven Whitehouse 		char c;
751ca6549afSSteven Whitehouse 		*num <<= 4;
752ca6549afSSteven Whitehouse 		if (get_user(c, &user_buffer[i]))
753ca6549afSSteven Whitehouse 			return -EFAULT;
75482fd5b5dSAndy Shevchenko 		value = hex_to_bin(c);
75582fd5b5dSAndy Shevchenko 		if (value >= 0)
75682fd5b5dSAndy Shevchenko 			*num |= value;
757ca6549afSSteven Whitehouse 		else
758ca6549afSSteven Whitehouse 			break;
759ca6549afSSteven Whitehouse 	}
760ca6549afSSteven Whitehouse 	return i;
761ca6549afSSteven Whitehouse }
762ca6549afSSteven Whitehouse 
763222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer,
764222f1806SLuiz Capitulino 			     unsigned int maxlen)
7651da177e4SLinus Torvalds {
7661da177e4SLinus Torvalds 	int i;
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 	for (i = 0; i < maxlen; i++) {
7691da177e4SLinus Torvalds 		char c;
7701da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7711da177e4SLinus Torvalds 			return -EFAULT;
7721da177e4SLinus Torvalds 		switch (c) {
7731da177e4SLinus Torvalds 		case '\"':
7741da177e4SLinus Torvalds 		case '\n':
7751da177e4SLinus Torvalds 		case '\r':
7761da177e4SLinus Torvalds 		case '\t':
7771da177e4SLinus Torvalds 		case ' ':
7781da177e4SLinus Torvalds 		case '=':
7791da177e4SLinus Torvalds 			break;
7801da177e4SLinus Torvalds 		default:
7811da177e4SLinus Torvalds 			goto done;
7823ff50b79SStephen Hemminger 		}
7831da177e4SLinus Torvalds 	}
7841da177e4SLinus Torvalds done:
7851da177e4SLinus Torvalds 	return i;
7861da177e4SLinus Torvalds }
7871da177e4SLinus Torvalds 
788bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen,
789bf0813bdSPaul Gortmaker 				unsigned long *num)
7901da177e4SLinus Torvalds {
791d6182223SPaul Gortmaker 	int i;
7921da177e4SLinus Torvalds 	*num = 0;
7931da177e4SLinus Torvalds 
794d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
7951da177e4SLinus Torvalds 		char c;
7961da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7971da177e4SLinus Torvalds 			return -EFAULT;
7981da177e4SLinus Torvalds 		if ((c >= '0') && (c <= '9')) {
7991da177e4SLinus Torvalds 			*num *= 10;
8001da177e4SLinus Torvalds 			*num += c - '0';
8011da177e4SLinus Torvalds 		} else
8021da177e4SLinus Torvalds 			break;
8031da177e4SLinus Torvalds 	}
8041da177e4SLinus Torvalds 	return i;
8051da177e4SLinus Torvalds }
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen)
8081da177e4SLinus Torvalds {
809d6182223SPaul Gortmaker 	int i;
8101da177e4SLinus Torvalds 
811d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
8121da177e4SLinus Torvalds 		char c;
8131da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
8141da177e4SLinus Torvalds 			return -EFAULT;
8151da177e4SLinus Torvalds 		switch (c) {
8161da177e4SLinus Torvalds 		case '\"':
8171da177e4SLinus Torvalds 		case '\n':
8181da177e4SLinus Torvalds 		case '\r':
8191da177e4SLinus Torvalds 		case '\t':
8201da177e4SLinus Torvalds 		case ' ':
8211da177e4SLinus Torvalds 			goto done_str;
8221da177e4SLinus Torvalds 		default:
8231da177e4SLinus Torvalds 			break;
8243ff50b79SStephen Hemminger 		}
8251da177e4SLinus Torvalds 	}
8261da177e4SLinus Torvalds done_str:
8271da177e4SLinus Torvalds 	return i;
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds 
830ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
831ca6549afSSteven Whitehouse {
83295c96174SEric Dumazet 	unsigned int n = 0;
833ca6549afSSteven Whitehouse 	char c;
834ca6549afSSteven Whitehouse 	ssize_t i = 0;
835ca6549afSSteven Whitehouse 	int len;
836ca6549afSSteven Whitehouse 
837ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = 0;
838ca6549afSSteven Whitehouse 	do {
839ca6549afSSteven Whitehouse 		__u32 tmp;
8401ca7768cSFrancesco Fondelli 		len = hex32_arg(&buffer[i], 8, &tmp);
841ca6549afSSteven Whitehouse 		if (len <= 0)
842ca6549afSSteven Whitehouse 			return len;
843ca6549afSSteven Whitehouse 		pkt_dev->labels[n] = htonl(tmp);
844ca6549afSSteven Whitehouse 		if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
845ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
846ca6549afSSteven Whitehouse 		i += len;
847ca6549afSSteven Whitehouse 		if (get_user(c, &buffer[i]))
848ca6549afSSteven Whitehouse 			return -EFAULT;
849ca6549afSSteven Whitehouse 		i++;
850ca6549afSSteven Whitehouse 		n++;
851ca6549afSSteven Whitehouse 		if (n >= MAX_MPLS_LABELS)
852ca6549afSSteven Whitehouse 			return -E2BIG;
853ca6549afSSteven Whitehouse 	} while (c == ',');
854ca6549afSSteven Whitehouse 
855ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = n;
856ca6549afSSteven Whitehouse 	return i;
857ca6549afSSteven Whitehouse }
858ca6549afSSteven Whitehouse 
859222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file,
860222f1806SLuiz Capitulino 			       const char __user * user_buffer, size_t count,
861222f1806SLuiz Capitulino 			       loff_t * offset)
8621da177e4SLinus Torvalds {
8638a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
864d50a6b56SStephen Hemminger 	struct pktgen_dev *pkt_dev = seq->private;
865d6182223SPaul Gortmaker 	int i, max, len;
8661da177e4SLinus Torvalds 	char name[16], valstr[32];
8671da177e4SLinus Torvalds 	unsigned long value = 0;
8681da177e4SLinus Torvalds 	char *pg_result = NULL;
8691da177e4SLinus Torvalds 	int tmp = 0;
8701da177e4SLinus Torvalds 	char buf[128];
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	pg_result = &(pkt_dev->result[0]);
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	if (count < 1) {
875294a0b7fSJoe Perches 		pr_warn("wrong command format\n");
8761da177e4SLinus Torvalds 		return -EINVAL;
8771da177e4SLinus Torvalds 	}
8781da177e4SLinus Torvalds 
879d6182223SPaul Gortmaker 	max = count;
880d6182223SPaul Gortmaker 	tmp = count_trail_chars(user_buffer, max);
8811da177e4SLinus Torvalds 	if (tmp < 0) {
882294a0b7fSJoe Perches 		pr_warn("illegal format\n");
8831da177e4SLinus Torvalds 		return tmp;
8841da177e4SLinus Torvalds 	}
885d6182223SPaul Gortmaker 	i = tmp;
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	/* Read variable name */
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
89063adc6fbSStephen Hemminger 	if (len < 0)
891222f1806SLuiz Capitulino 		return len;
89263adc6fbSStephen Hemminger 
8931da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
8941da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
8951da177e4SLinus Torvalds 		return -EFAULT;
8961da177e4SLinus Torvalds 	i += len;
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds 	max = count - i;
8991da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
9001da177e4SLinus Torvalds 	if (len < 0)
9011da177e4SLinus Torvalds 		return len;
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 	i += len;
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds 	if (debug) {
90686c2c0a8SDmitry Torokhov 		size_t copy = min_t(size_t, count, 1023);
907448d7b5dSNelson Elhage 		char tb[copy + 1];
908448d7b5dSNelson Elhage 		if (copy_from_user(tb, user_buffer, copy))
9091da177e4SLinus Torvalds 			return -EFAULT;
910448d7b5dSNelson Elhage 		tb[copy] = 0;
911f342cda7SJoe Perches 		pr_debug("%s,%lu  buffer -:%s:-\n",
912f342cda7SJoe Perches 			 name, (unsigned long)count, tb);
9131da177e4SLinus Torvalds 	}
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	if (!strcmp(name, "min_pkt_size")) {
9161da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
91763adc6fbSStephen Hemminger 		if (len < 0)
918222f1806SLuiz Capitulino 			return len;
91963adc6fbSStephen Hemminger 
9201da177e4SLinus Torvalds 		i += len;
9211da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9221da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9231da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9241da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9251da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9261da177e4SLinus Torvalds 		}
927222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: min_pkt_size=%u",
928222f1806SLuiz Capitulino 			pkt_dev->min_pkt_size);
9291da177e4SLinus Torvalds 		return count;
9301da177e4SLinus Torvalds 	}
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	if (!strcmp(name, "max_pkt_size")) {
9331da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
93463adc6fbSStephen Hemminger 		if (len < 0)
935222f1806SLuiz Capitulino 			return len;
93663adc6fbSStephen Hemminger 
9371da177e4SLinus Torvalds 		i += len;
9381da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9391da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9401da177e4SLinus Torvalds 		if (value != pkt_dev->max_pkt_size) {
9411da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9421da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9431da177e4SLinus Torvalds 		}
944222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: max_pkt_size=%u",
945222f1806SLuiz Capitulino 			pkt_dev->max_pkt_size);
9461da177e4SLinus Torvalds 		return count;
9471da177e4SLinus Torvalds 	}
9481da177e4SLinus Torvalds 
9491da177e4SLinus Torvalds 	/* Shortcut for min = max */
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	if (!strcmp(name, "pkt_size")) {
9521da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
95363adc6fbSStephen Hemminger 		if (len < 0)
954222f1806SLuiz Capitulino 			return len;
95563adc6fbSStephen Hemminger 
9561da177e4SLinus Torvalds 		i += len;
9571da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9581da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9591da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9601da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9611da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9621da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9631da177e4SLinus Torvalds 		}
9641da177e4SLinus Torvalds 		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
9651da177e4SLinus Torvalds 		return count;
9661da177e4SLinus Torvalds 	}
9671da177e4SLinus Torvalds 
9681da177e4SLinus Torvalds 	if (!strcmp(name, "debug")) {
9691da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
97063adc6fbSStephen Hemminger 		if (len < 0)
971222f1806SLuiz Capitulino 			return len;
97263adc6fbSStephen Hemminger 
9731da177e4SLinus Torvalds 		i += len;
9741da177e4SLinus Torvalds 		debug = value;
9751da177e4SLinus Torvalds 		sprintf(pg_result, "OK: debug=%u", debug);
9761da177e4SLinus Torvalds 		return count;
9771da177e4SLinus Torvalds 	}
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 	if (!strcmp(name, "frags")) {
9801da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
98163adc6fbSStephen Hemminger 		if (len < 0)
982222f1806SLuiz Capitulino 			return len;
98363adc6fbSStephen Hemminger 
9841da177e4SLinus Torvalds 		i += len;
9851da177e4SLinus Torvalds 		pkt_dev->nfrags = value;
9861da177e4SLinus Torvalds 		sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
9871da177e4SLinus Torvalds 		return count;
9881da177e4SLinus Torvalds 	}
9891da177e4SLinus Torvalds 	if (!strcmp(name, "delay")) {
9901da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
99163adc6fbSStephen Hemminger 		if (len < 0)
992222f1806SLuiz Capitulino 			return len;
99363adc6fbSStephen Hemminger 
9941da177e4SLinus Torvalds 		i += len;
995fd29cf72SStephen Hemminger 		if (value == 0x7FFFFFFF)
996fd29cf72SStephen Hemminger 			pkt_dev->delay = ULLONG_MAX;
997fd29cf72SStephen Hemminger 		else
9989240d715SEric Dumazet 			pkt_dev->delay = (u64)value;
999fd29cf72SStephen Hemminger 
1000fd29cf72SStephen Hemminger 		sprintf(pg_result, "OK: delay=%llu",
1001fd29cf72SStephen Hemminger 			(unsigned long long) pkt_dev->delay);
10021da177e4SLinus Torvalds 		return count;
10031da177e4SLinus Torvalds 	}
100443d28b65SDaniel Turull 	if (!strcmp(name, "rate")) {
100543d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
100643d28b65SDaniel Turull 		if (len < 0)
100743d28b65SDaniel Turull 			return len;
100843d28b65SDaniel Turull 
100943d28b65SDaniel Turull 		i += len;
101043d28b65SDaniel Turull 		if (!value)
101143d28b65SDaniel Turull 			return len;
101243d28b65SDaniel Turull 		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
101343d28b65SDaniel Turull 		if (debug)
1014f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
101543d28b65SDaniel Turull 
101643d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
101743d28b65SDaniel Turull 		return count;
101843d28b65SDaniel Turull 	}
101943d28b65SDaniel Turull 	if (!strcmp(name, "ratep")) {
102043d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
102143d28b65SDaniel Turull 		if (len < 0)
102243d28b65SDaniel Turull 			return len;
102343d28b65SDaniel Turull 
102443d28b65SDaniel Turull 		i += len;
102543d28b65SDaniel Turull 		if (!value)
102643d28b65SDaniel Turull 			return len;
102743d28b65SDaniel Turull 		pkt_dev->delay = NSEC_PER_SEC/value;
102843d28b65SDaniel Turull 		if (debug)
1029f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
103043d28b65SDaniel Turull 
103143d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
103243d28b65SDaniel Turull 		return count;
103343d28b65SDaniel Turull 	}
10341da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_min")) {
10351da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
103663adc6fbSStephen Hemminger 		if (len < 0)
1037222f1806SLuiz Capitulino 			return len;
103863adc6fbSStephen Hemminger 
10391da177e4SLinus Torvalds 		i += len;
10401da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_min) {
10411da177e4SLinus Torvalds 			pkt_dev->udp_src_min = value;
10421da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10431da177e4SLinus Torvalds 		}
10441da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
10451da177e4SLinus Torvalds 		return count;
10461da177e4SLinus Torvalds 	}
10471da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_min")) {
10481da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
104963adc6fbSStephen Hemminger 		if (len < 0)
1050222f1806SLuiz Capitulino 			return len;
105163adc6fbSStephen Hemminger 
10521da177e4SLinus Torvalds 		i += len;
10531da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_min) {
10541da177e4SLinus Torvalds 			pkt_dev->udp_dst_min = value;
10551da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10561da177e4SLinus Torvalds 		}
10571da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
10581da177e4SLinus Torvalds 		return count;
10591da177e4SLinus Torvalds 	}
10601da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_max")) {
10611da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
106263adc6fbSStephen Hemminger 		if (len < 0)
1063222f1806SLuiz Capitulino 			return len;
106463adc6fbSStephen Hemminger 
10651da177e4SLinus Torvalds 		i += len;
10661da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_max) {
10671da177e4SLinus Torvalds 			pkt_dev->udp_src_max = value;
10681da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10691da177e4SLinus Torvalds 		}
10701da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
10711da177e4SLinus Torvalds 		return count;
10721da177e4SLinus Torvalds 	}
10731da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_max")) {
10741da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
107563adc6fbSStephen Hemminger 		if (len < 0)
1076222f1806SLuiz Capitulino 			return len;
107763adc6fbSStephen Hemminger 
10781da177e4SLinus Torvalds 		i += len;
10791da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_max) {
10801da177e4SLinus Torvalds 			pkt_dev->udp_dst_max = value;
10811da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10821da177e4SLinus Torvalds 		}
10831da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
10841da177e4SLinus Torvalds 		return count;
10851da177e4SLinus Torvalds 	}
10861da177e4SLinus Torvalds 	if (!strcmp(name, "clone_skb")) {
10871da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
108863adc6fbSStephen Hemminger 		if (len < 0)
1089222f1806SLuiz Capitulino 			return len;
1090d8873315SNeil Horman 		if ((value > 0) &&
109162f64aedSAlexei Starovoitov 		    ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) ||
109262f64aedSAlexei Starovoitov 		     !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
1093d8873315SNeil Horman 			return -ENOTSUPP;
10941da177e4SLinus Torvalds 		i += len;
10951da177e4SLinus Torvalds 		pkt_dev->clone_skb = value;
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 		sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
10981da177e4SLinus Torvalds 		return count;
10991da177e4SLinus Torvalds 	}
11001da177e4SLinus Torvalds 	if (!strcmp(name, "count")) {
11011da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
110263adc6fbSStephen Hemminger 		if (len < 0)
1103222f1806SLuiz Capitulino 			return len;
110463adc6fbSStephen Hemminger 
11051da177e4SLinus Torvalds 		i += len;
11061da177e4SLinus Torvalds 		pkt_dev->count = value;
11071da177e4SLinus Torvalds 		sprintf(pg_result, "OK: count=%llu",
11081da177e4SLinus Torvalds 			(unsigned long long)pkt_dev->count);
11091da177e4SLinus Torvalds 		return count;
11101da177e4SLinus Torvalds 	}
11111da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac_count")) {
11121da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
111363adc6fbSStephen Hemminger 		if (len < 0)
1114222f1806SLuiz Capitulino 			return len;
111563adc6fbSStephen Hemminger 
11161da177e4SLinus Torvalds 		i += len;
11171da177e4SLinus Torvalds 		if (pkt_dev->src_mac_count != value) {
11181da177e4SLinus Torvalds 			pkt_dev->src_mac_count = value;
11191da177e4SLinus Torvalds 			pkt_dev->cur_src_mac_offset = 0;
11201da177e4SLinus Torvalds 		}
1121222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: src_mac_count=%d",
1122222f1806SLuiz Capitulino 			pkt_dev->src_mac_count);
11231da177e4SLinus Torvalds 		return count;
11241da177e4SLinus Torvalds 	}
11251da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac_count")) {
11261da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
112763adc6fbSStephen Hemminger 		if (len < 0)
1128222f1806SLuiz Capitulino 			return len;
112963adc6fbSStephen Hemminger 
11301da177e4SLinus Torvalds 		i += len;
11311da177e4SLinus Torvalds 		if (pkt_dev->dst_mac_count != value) {
11321da177e4SLinus Torvalds 			pkt_dev->dst_mac_count = value;
11331da177e4SLinus Torvalds 			pkt_dev->cur_dst_mac_offset = 0;
11341da177e4SLinus Torvalds 		}
1135222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: dst_mac_count=%d",
1136222f1806SLuiz Capitulino 			pkt_dev->dst_mac_count);
11371da177e4SLinus Torvalds 		return count;
11381da177e4SLinus Torvalds 	}
113938b2cf29SAlexei Starovoitov 	if (!strcmp(name, "burst")) {
114038b2cf29SAlexei Starovoitov 		len = num_arg(&user_buffer[i], 10, &value);
114138b2cf29SAlexei Starovoitov 		if (len < 0)
114238b2cf29SAlexei Starovoitov 			return len;
114338b2cf29SAlexei Starovoitov 
114438b2cf29SAlexei Starovoitov 		i += len;
114562f64aedSAlexei Starovoitov 		if ((value > 1) && (pkt_dev->xmit_mode == M_START_XMIT) &&
114652d6c8c6SEric Dumazet 		    (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
114752d6c8c6SEric Dumazet 			return -ENOTSUPP;
114838b2cf29SAlexei Starovoitov 		pkt_dev->burst = value < 1 ? 1 : value;
114938b2cf29SAlexei Starovoitov 		sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
115038b2cf29SAlexei Starovoitov 		return count;
115138b2cf29SAlexei Starovoitov 	}
1152e99b99b4SRobert Olsson 	if (!strcmp(name, "node")) {
1153e99b99b4SRobert Olsson 		len = num_arg(&user_buffer[i], 10, &value);
1154e99b99b4SRobert Olsson 		if (len < 0)
1155e99b99b4SRobert Olsson 			return len;
1156e99b99b4SRobert Olsson 
1157e99b99b4SRobert Olsson 		i += len;
1158e99b99b4SRobert Olsson 
1159e99b99b4SRobert Olsson 		if (node_possible(value)) {
1160e99b99b4SRobert Olsson 			pkt_dev->node = value;
1161e99b99b4SRobert Olsson 			sprintf(pg_result, "OK: node=%d", pkt_dev->node);
116226ad7879SEric Dumazet 			if (pkt_dev->page) {
116326ad7879SEric Dumazet 				put_page(pkt_dev->page);
116426ad7879SEric Dumazet 				pkt_dev->page = NULL;
116526ad7879SEric Dumazet 			}
1166e99b99b4SRobert Olsson 		}
1167e99b99b4SRobert Olsson 		else
1168e99b99b4SRobert Olsson 			sprintf(pg_result, "ERROR: node not possible");
1169e99b99b4SRobert Olsson 		return count;
1170e99b99b4SRobert Olsson 	}
117162f64aedSAlexei Starovoitov 	if (!strcmp(name, "xmit_mode")) {
117262f64aedSAlexei Starovoitov 		char f[32];
117362f64aedSAlexei Starovoitov 
117462f64aedSAlexei Starovoitov 		memset(f, 0, 32);
117562f64aedSAlexei Starovoitov 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
117662f64aedSAlexei Starovoitov 		if (len < 0)
117762f64aedSAlexei Starovoitov 			return len;
117862f64aedSAlexei Starovoitov 
117962f64aedSAlexei Starovoitov 		if (copy_from_user(f, &user_buffer[i], len))
118062f64aedSAlexei Starovoitov 			return -EFAULT;
118162f64aedSAlexei Starovoitov 		i += len;
118262f64aedSAlexei Starovoitov 
118362f64aedSAlexei Starovoitov 		if (strcmp(f, "start_xmit") == 0) {
118462f64aedSAlexei Starovoitov 			pkt_dev->xmit_mode = M_START_XMIT;
118562f64aedSAlexei Starovoitov 		} else if (strcmp(f, "netif_receive") == 0) {
118662f64aedSAlexei Starovoitov 			/* clone_skb set earlier, not supported in this mode */
118762f64aedSAlexei Starovoitov 			if (pkt_dev->clone_skb > 0)
118862f64aedSAlexei Starovoitov 				return -ENOTSUPP;
118962f64aedSAlexei Starovoitov 
119062f64aedSAlexei Starovoitov 			pkt_dev->xmit_mode = M_NETIF_RECEIVE;
11919eea9222SAlexei Starovoitov 
11929eea9222SAlexei Starovoitov 			/* make sure new packet is allocated every time
11939eea9222SAlexei Starovoitov 			 * pktgen_xmit() is called
11949eea9222SAlexei Starovoitov 			 */
11959eea9222SAlexei Starovoitov 			pkt_dev->last_ok = 1;
11969eea9222SAlexei Starovoitov 
11979eea9222SAlexei Starovoitov 			/* override clone_skb if user passed default value
11989eea9222SAlexei Starovoitov 			 * at module loading time
11999eea9222SAlexei Starovoitov 			 */
12009eea9222SAlexei Starovoitov 			pkt_dev->clone_skb = 0;
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")) {
12111da177e4SLinus Torvalds 		char f[32];
12121da177e4SLinus Torvalds 		memset(f, 0, 32);
12131da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
121463adc6fbSStephen Hemminger 		if (len < 0)
1215222f1806SLuiz Capitulino 			return len;
121663adc6fbSStephen Hemminger 
12171da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
12181da177e4SLinus Torvalds 			return -EFAULT;
12191da177e4SLinus Torvalds 		i += len;
12201da177e4SLinus Torvalds 		if (strcmp(f, "IPSRC_RND") == 0)
12211da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPSRC_RND;
12221da177e4SLinus Torvalds 
12231da177e4SLinus Torvalds 		else if (strcmp(f, "!IPSRC_RND") == 0)
12241da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPSRC_RND;
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds 		else if (strcmp(f, "TXSIZE_RND") == 0)
12271da177e4SLinus Torvalds 			pkt_dev->flags |= F_TXSIZE_RND;
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 		else if (strcmp(f, "!TXSIZE_RND") == 0)
12301da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_TXSIZE_RND;
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 		else if (strcmp(f, "IPDST_RND") == 0)
12331da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPDST_RND;
12341da177e4SLinus Torvalds 
12351da177e4SLinus Torvalds 		else if (strcmp(f, "!IPDST_RND") == 0)
12361da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPDST_RND;
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds 		else if (strcmp(f, "UDPSRC_RND") == 0)
12391da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPSRC_RND;
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPSRC_RND") == 0)
12421da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPSRC_RND;
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 		else if (strcmp(f, "UDPDST_RND") == 0)
12451da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPDST_RND;
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPDST_RND") == 0)
12481da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPDST_RND;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 		else if (strcmp(f, "MACSRC_RND") == 0)
12511da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACSRC_RND;
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds 		else if (strcmp(f, "!MACSRC_RND") == 0)
12541da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACSRC_RND;
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds 		else if (strcmp(f, "MACDST_RND") == 0)
12571da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACDST_RND;
12581da177e4SLinus Torvalds 
12591da177e4SLinus Torvalds 		else if (strcmp(f, "!MACDST_RND") == 0)
12601da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACDST_RND;
12611da177e4SLinus Torvalds 
1262ca6549afSSteven Whitehouse 		else if (strcmp(f, "MPLS_RND") == 0)
1263ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
1264ca6549afSSteven Whitehouse 
1265ca6549afSSteven Whitehouse 		else if (strcmp(f, "!MPLS_RND") == 0)
1266ca6549afSSteven Whitehouse 			pkt_dev->flags &= ~F_MPLS_RND;
1267ca6549afSSteven Whitehouse 
126834954ddcSFrancesco Fondelli 		else if (strcmp(f, "VID_RND") == 0)
126934954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_VID_RND;
127034954ddcSFrancesco Fondelli 
127134954ddcSFrancesco Fondelli 		else if (strcmp(f, "!VID_RND") == 0)
127234954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_VID_RND;
127334954ddcSFrancesco Fondelli 
127434954ddcSFrancesco Fondelli 		else if (strcmp(f, "SVID_RND") == 0)
127534954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_SVID_RND;
127634954ddcSFrancesco Fondelli 
127734954ddcSFrancesco Fondelli 		else if (strcmp(f, "!SVID_RND") == 0)
127834954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_SVID_RND;
127934954ddcSFrancesco Fondelli 
1280007a531bSJamal Hadi Salim 		else if (strcmp(f, "FLOW_SEQ") == 0)
1281007a531bSJamal Hadi Salim 			pkt_dev->flags |= F_FLOW_SEQ;
1282007a531bSJamal Hadi Salim 
128345b270f8SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_RND") == 0)
128445b270f8SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_RND;
128545b270f8SRobert Olsson 
128645b270f8SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_RND") == 0)
128745b270f8SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_RND;
1288e6fce5b9SRobert Olsson 
1289e6fce5b9SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_CPU") == 0)
1290e6fce5b9SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_CPU;
1291e6fce5b9SRobert Olsson 
1292e6fce5b9SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_CPU") == 0)
1293e6fce5b9SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
1294a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
1295a553e4a6SJamal Hadi Salim 		else if (strcmp(f, "IPSEC") == 0)
1296a553e4a6SJamal Hadi Salim 			pkt_dev->flags |= F_IPSEC_ON;
1297a553e4a6SJamal Hadi Salim #endif
1298a553e4a6SJamal Hadi Salim 
12991ca7768cSFrancesco Fondelli 		else if (strcmp(f, "!IPV6") == 0)
13001ca7768cSFrancesco Fondelli 			pkt_dev->flags &= ~F_IPV6;
13011ca7768cSFrancesco Fondelli 
1302e99b99b4SRobert Olsson 		else if (strcmp(f, "NODE_ALLOC") == 0)
1303e99b99b4SRobert Olsson 			pkt_dev->flags |= F_NODE;
1304e99b99b4SRobert Olsson 
1305e99b99b4SRobert Olsson 		else if (strcmp(f, "!NODE_ALLOC") == 0)
1306e99b99b4SRobert Olsson 			pkt_dev->flags &= ~F_NODE;
1307e99b99b4SRobert Olsson 
1308c26bf4a5SThomas Graf 		else if (strcmp(f, "UDPCSUM") == 0)
1309c26bf4a5SThomas Graf 			pkt_dev->flags |= F_UDPCSUM;
1310c26bf4a5SThomas Graf 
1311c26bf4a5SThomas Graf 		else if (strcmp(f, "!UDPCSUM") == 0)
1312c26bf4a5SThomas Graf 			pkt_dev->flags &= ~F_UDPCSUM;
1313c26bf4a5SThomas Graf 
1314afb84b62SJesper Dangaard Brouer 		else if (strcmp(f, "NO_TIMESTAMP") == 0)
1315afb84b62SJesper Dangaard Brouer 			pkt_dev->flags |= F_NO_TIMESTAMP;
1316afb84b62SJesper Dangaard Brouer 
1317f1f00d8fSJesper Dangaard Brouer 		else if (strcmp(f, "!NO_TIMESTAMP") == 0)
1318f1f00d8fSJesper Dangaard Brouer 			pkt_dev->flags &= ~F_NO_TIMESTAMP;
1319f1f00d8fSJesper Dangaard Brouer 
13201da177e4SLinus Torvalds 		else {
1321222f1806SLuiz Capitulino 			sprintf(pg_result,
1322222f1806SLuiz Capitulino 				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
13231da177e4SLinus Torvalds 				f,
13241ca7768cSFrancesco Fondelli 				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
132572f8e06fSMathias Krause 				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
132672f8e06fSMathias Krause 				"MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
132772f8e06fSMathias Krause 				"QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
1328afb84b62SJesper Dangaard Brouer 				"NO_TIMESTAMP, "
132972f8e06fSMathias Krause #ifdef CONFIG_XFRM
133072f8e06fSMathias Krause 				"IPSEC, "
133172f8e06fSMathias Krause #endif
133272f8e06fSMathias Krause 				"NODE_ALLOC\n");
13331da177e4SLinus Torvalds 			return count;
13341da177e4SLinus Torvalds 		}
13351da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
13361da177e4SLinus Torvalds 		return count;
13371da177e4SLinus Torvalds 	}
13381da177e4SLinus Torvalds 	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
13391da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
134063adc6fbSStephen Hemminger 		if (len < 0)
1341222f1806SLuiz Capitulino 			return len;
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13441da177e4SLinus Torvalds 			return -EFAULT;
13451da177e4SLinus Torvalds 		buf[len] = 0;
13461da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_min) != 0) {
13471da177e4SLinus Torvalds 			memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
13481da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_min, buf, len);
13491da177e4SLinus Torvalds 			pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
13501da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_min;
13511da177e4SLinus Torvalds 		}
13521da177e4SLinus Torvalds 		if (debug)
1353f342cda7SJoe Perches 			pr_debug("dst_min set to: %s\n", pkt_dev->dst_min);
13541da177e4SLinus Torvalds 		i += len;
13551da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
13561da177e4SLinus Torvalds 		return count;
13571da177e4SLinus Torvalds 	}
13581da177e4SLinus Torvalds 	if (!strcmp(name, "dst_max")) {
13591da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
136063adc6fbSStephen Hemminger 		if (len < 0)
1361222f1806SLuiz Capitulino 			return len;
136263adc6fbSStephen Hemminger 
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13651da177e4SLinus Torvalds 			return -EFAULT;
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 		buf[len] = 0;
13681da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_max) != 0) {
13691da177e4SLinus Torvalds 			memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
13701da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_max, buf, len);
13711da177e4SLinus Torvalds 			pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
13721da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_max;
13731da177e4SLinus Torvalds 		}
13741da177e4SLinus Torvalds 		if (debug)
1375f342cda7SJoe Perches 			pr_debug("dst_max set to: %s\n", pkt_dev->dst_max);
13761da177e4SLinus Torvalds 		i += len;
13771da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
13781da177e4SLinus Torvalds 		return count;
13791da177e4SLinus Torvalds 	}
13801da177e4SLinus Torvalds 	if (!strcmp(name, "dst6")) {
13811da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1382222f1806SLuiz Capitulino 		if (len < 0)
1383222f1806SLuiz Capitulino 			return len;
13841da177e4SLinus Torvalds 
13851da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13881da177e4SLinus Torvalds 			return -EFAULT;
13891da177e4SLinus Torvalds 		buf[len] = 0;
13901da177e4SLinus Torvalds 
1391c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL);
139247a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
13931da177e4SLinus Torvalds 
13944e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr;
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 		if (debug)
1397f342cda7SJoe Perches 			pr_debug("dst6 set to: %s\n", buf);
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds 		i += len;
14001da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6=%s", buf);
14011da177e4SLinus Torvalds 		return count;
14021da177e4SLinus Torvalds 	}
14031da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_min")) {
14041da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1405222f1806SLuiz Capitulino 		if (len < 0)
1406222f1806SLuiz Capitulino 			return len;
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14091da177e4SLinus Torvalds 
14101da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14111da177e4SLinus Torvalds 			return -EFAULT;
14121da177e4SLinus Torvalds 		buf[len] = 0;
14131da177e4SLinus Torvalds 
1414c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL);
141547a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
14161da177e4SLinus Torvalds 
14174e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr;
14181da177e4SLinus Torvalds 		if (debug)
1419f342cda7SJoe Perches 			pr_debug("dst6_min set to: %s\n", buf);
14201da177e4SLinus Torvalds 
14211da177e4SLinus Torvalds 		i += len;
14221da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_min=%s", buf);
14231da177e4SLinus Torvalds 		return count;
14241da177e4SLinus Torvalds 	}
14251da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_max")) {
14261da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1427222f1806SLuiz Capitulino 		if (len < 0)
1428222f1806SLuiz Capitulino 			return len;
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14331da177e4SLinus Torvalds 			return -EFAULT;
14341da177e4SLinus Torvalds 		buf[len] = 0;
14351da177e4SLinus Torvalds 
1436c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL);
143747a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
14381da177e4SLinus Torvalds 
14391da177e4SLinus Torvalds 		if (debug)
1440f342cda7SJoe Perches 			pr_debug("dst6_max set to: %s\n", buf);
14411da177e4SLinus Torvalds 
14421da177e4SLinus Torvalds 		i += len;
14431da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_max=%s", buf);
14441da177e4SLinus Torvalds 		return count;
14451da177e4SLinus Torvalds 	}
14461da177e4SLinus Torvalds 	if (!strcmp(name, "src6")) {
14471da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1448222f1806SLuiz Capitulino 		if (len < 0)
1449222f1806SLuiz Capitulino 			return len;
14501da177e4SLinus Torvalds 
14511da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14541da177e4SLinus Torvalds 			return -EFAULT;
14551da177e4SLinus Torvalds 		buf[len] = 0;
14561da177e4SLinus Torvalds 
1457c468fb13SAmerigo Wang 		in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL);
145847a0200dSAlexey Dobriyan 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
14591da177e4SLinus Torvalds 
14604e3fd7a0SAlexey Dobriyan 		pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr;
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 		if (debug)
1463f342cda7SJoe Perches 			pr_debug("src6 set to: %s\n", buf);
14641da177e4SLinus Torvalds 
14651da177e4SLinus Torvalds 		i += len;
14661da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src6=%s", buf);
14671da177e4SLinus Torvalds 		return count;
14681da177e4SLinus Torvalds 	}
14691da177e4SLinus Torvalds 	if (!strcmp(name, "src_min")) {
14701da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
147163adc6fbSStephen Hemminger 		if (len < 0)
1472222f1806SLuiz Capitulino 			return len;
147363adc6fbSStephen Hemminger 
14741da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14751da177e4SLinus Torvalds 			return -EFAULT;
14761da177e4SLinus Torvalds 		buf[len] = 0;
14771da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_min) != 0) {
14781da177e4SLinus Torvalds 			memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
14791da177e4SLinus Torvalds 			strncpy(pkt_dev->src_min, buf, len);
14801da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
14811da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_min;
14821da177e4SLinus Torvalds 		}
14831da177e4SLinus Torvalds 		if (debug)
1484f342cda7SJoe Perches 			pr_debug("src_min set to: %s\n", pkt_dev->src_min);
14851da177e4SLinus Torvalds 		i += len;
14861da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
14871da177e4SLinus Torvalds 		return count;
14881da177e4SLinus Torvalds 	}
14891da177e4SLinus Torvalds 	if (!strcmp(name, "src_max")) {
14901da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
149163adc6fbSStephen Hemminger 		if (len < 0)
1492222f1806SLuiz Capitulino 			return len;
149363adc6fbSStephen Hemminger 
14941da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14951da177e4SLinus Torvalds 			return -EFAULT;
14961da177e4SLinus Torvalds 		buf[len] = 0;
14971da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_max) != 0) {
14981da177e4SLinus Torvalds 			memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
14991da177e4SLinus Torvalds 			strncpy(pkt_dev->src_max, buf, len);
15001da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
15011da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_max;
15021da177e4SLinus Torvalds 		}
15031da177e4SLinus Torvalds 		if (debug)
1504f342cda7SJoe Perches 			pr_debug("src_max set to: %s\n", pkt_dev->src_max);
15051da177e4SLinus Torvalds 		i += len;
15061da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
15071da177e4SLinus Torvalds 		return count;
15081da177e4SLinus Torvalds 	}
15091da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac")) {
15101da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
151163adc6fbSStephen Hemminger 		if (len < 0)
1512222f1806SLuiz Capitulino 			return len;
151363adc6fbSStephen Hemminger 
15141da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
15151da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
15161da177e4SLinus Torvalds 			return -EFAULT;
15171da177e4SLinus Torvalds 
15184940fc88SAlexey Dobriyan 		if (!mac_pton(valstr, pkt_dev->dst_mac))
15194940fc88SAlexey Dobriyan 			return -EINVAL;
15201da177e4SLinus Torvalds 		/* Set up Dest MAC */
15219ea08b12SJoe Perches 		ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac);
15221da177e4SLinus Torvalds 
15234940fc88SAlexey Dobriyan 		sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
15241da177e4SLinus Torvalds 		return count;
15251da177e4SLinus Torvalds 	}
15261da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac")) {
15271da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
152863adc6fbSStephen Hemminger 		if (len < 0)
1529222f1806SLuiz Capitulino 			return len;
153063adc6fbSStephen Hemminger 
15311da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
15321da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
15331da177e4SLinus Torvalds 			return -EFAULT;
15341da177e4SLinus Torvalds 
15354940fc88SAlexey Dobriyan 		if (!mac_pton(valstr, pkt_dev->src_mac))
15364940fc88SAlexey Dobriyan 			return -EINVAL;
1537ce5d0b47SAdit Ranadive 		/* Set up Src MAC */
15389ea08b12SJoe Perches 		ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac);
1539ce5d0b47SAdit Ranadive 
15404940fc88SAlexey Dobriyan 		sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
15411da177e4SLinus Torvalds 		return count;
15421da177e4SLinus Torvalds 	}
15431da177e4SLinus Torvalds 
15441da177e4SLinus Torvalds 	if (!strcmp(name, "clear_counters")) {
15451da177e4SLinus Torvalds 		pktgen_clear_counters(pkt_dev);
15461da177e4SLinus Torvalds 		sprintf(pg_result, "OK: Clearing counters.\n");
15471da177e4SLinus Torvalds 		return count;
15481da177e4SLinus Torvalds 	}
15491da177e4SLinus Torvalds 
15501da177e4SLinus Torvalds 	if (!strcmp(name, "flows")) {
15511da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
155263adc6fbSStephen Hemminger 		if (len < 0)
1553222f1806SLuiz Capitulino 			return len;
155463adc6fbSStephen Hemminger 
15551da177e4SLinus Torvalds 		i += len;
15561da177e4SLinus Torvalds 		if (value > MAX_CFLOWS)
15571da177e4SLinus Torvalds 			value = MAX_CFLOWS;
15581da177e4SLinus Torvalds 
15591da177e4SLinus Torvalds 		pkt_dev->cflows = value;
15601da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
15611da177e4SLinus Torvalds 		return count;
15621da177e4SLinus Torvalds 	}
15636bae9190SFan Du #ifdef CONFIG_XFRM
1564de4aee7dSFan Du 	if (!strcmp(name, "spi")) {
1565de4aee7dSFan Du 		len = num_arg(&user_buffer[i], 10, &value);
1566de4aee7dSFan Du 		if (len < 0)
1567de4aee7dSFan Du 			return len;
1568de4aee7dSFan Du 
1569de4aee7dSFan Du 		i += len;
1570de4aee7dSFan Du 		pkt_dev->spi = value;
1571de4aee7dSFan Du 		sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
1572de4aee7dSFan Du 		return count;
1573de4aee7dSFan Du 	}
15746bae9190SFan Du #endif
15751da177e4SLinus Torvalds 	if (!strcmp(name, "flowlen")) {
15761da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
157763adc6fbSStephen Hemminger 		if (len < 0)
1578222f1806SLuiz Capitulino 			return len;
157963adc6fbSStephen Hemminger 
15801da177e4SLinus Torvalds 		i += len;
15811da177e4SLinus Torvalds 		pkt_dev->lflow = value;
15821da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
15831da177e4SLinus Torvalds 		return count;
15841da177e4SLinus Torvalds 	}
15851da177e4SLinus Torvalds 
158645b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_min")) {
158745b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
158863adc6fbSStephen Hemminger 		if (len < 0)
158945b270f8SRobert Olsson 			return len;
159063adc6fbSStephen Hemminger 
159145b270f8SRobert Olsson 		i += len;
159245b270f8SRobert Olsson 		pkt_dev->queue_map_min = value;
159345b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
159445b270f8SRobert Olsson 		return count;
159545b270f8SRobert Olsson 	}
159645b270f8SRobert Olsson 
159745b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_max")) {
159845b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
159963adc6fbSStephen Hemminger 		if (len < 0)
160045b270f8SRobert Olsson 			return len;
160163adc6fbSStephen Hemminger 
160245b270f8SRobert Olsson 		i += len;
160345b270f8SRobert Olsson 		pkt_dev->queue_map_max = value;
160445b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
160545b270f8SRobert Olsson 		return count;
160645b270f8SRobert Olsson 	}
160745b270f8SRobert Olsson 
1608ca6549afSSteven Whitehouse 	if (!strcmp(name, "mpls")) {
160995c96174SEric Dumazet 		unsigned int n, cnt;
1610cfcabdccSStephen Hemminger 
1611ca6549afSSteven Whitehouse 		len = get_labels(&user_buffer[i], pkt_dev);
1612cfcabdccSStephen Hemminger 		if (len < 0)
1613cfcabdccSStephen Hemminger 			return len;
1614ca6549afSSteven Whitehouse 		i += len;
1615cfcabdccSStephen Hemminger 		cnt = sprintf(pg_result, "OK: mpls=");
1616ca6549afSSteven Whitehouse 		for (n = 0; n < pkt_dev->nr_labels; n++)
1617cfcabdccSStephen Hemminger 			cnt += sprintf(pg_result + cnt,
1618ca6549afSSteven Whitehouse 				       "%08x%s", ntohl(pkt_dev->labels[n]),
1619ca6549afSSteven Whitehouse 				       n == pkt_dev->nr_labels-1 ? "" : ",");
162034954ddcSFrancesco Fondelli 
162134954ddcSFrancesco Fondelli 		if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
162234954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
162334954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
162434954ddcSFrancesco Fondelli 
162534954ddcSFrancesco Fondelli 			if (debug)
1626f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN auto turned off\n");
162734954ddcSFrancesco Fondelli 		}
162834954ddcSFrancesco Fondelli 		return count;
162934954ddcSFrancesco Fondelli 	}
163034954ddcSFrancesco Fondelli 
163134954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_id")) {
163234954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
163363adc6fbSStephen Hemminger 		if (len < 0)
163434954ddcSFrancesco Fondelli 			return len;
163563adc6fbSStephen Hemminger 
163634954ddcSFrancesco Fondelli 		i += len;
163734954ddcSFrancesco Fondelli 		if (value <= 4095) {
163834954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = value;  /* turn on VLAN */
163934954ddcSFrancesco Fondelli 
164034954ddcSFrancesco Fondelli 			if (debug)
1641f342cda7SJoe Perches 				pr_debug("VLAN turned on\n");
164234954ddcSFrancesco Fondelli 
164334954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
1644f342cda7SJoe Perches 				pr_debug("MPLS auto turned off\n");
164534954ddcSFrancesco Fondelli 
164634954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
164734954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
164834954ddcSFrancesco Fondelli 		} else {
164934954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
165034954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
165134954ddcSFrancesco Fondelli 
165234954ddcSFrancesco Fondelli 			if (debug)
1653f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN turned off\n");
165434954ddcSFrancesco Fondelli 		}
165534954ddcSFrancesco Fondelli 		return count;
165634954ddcSFrancesco Fondelli 	}
165734954ddcSFrancesco Fondelli 
165834954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_p")) {
165934954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
166063adc6fbSStephen Hemminger 		if (len < 0)
166134954ddcSFrancesco Fondelli 			return len;
166263adc6fbSStephen Hemminger 
166334954ddcSFrancesco Fondelli 		i += len;
166434954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
166534954ddcSFrancesco Fondelli 			pkt_dev->vlan_p = value;
166634954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
166734954ddcSFrancesco Fondelli 		} else {
166834954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_p must be 0-7");
166934954ddcSFrancesco Fondelli 		}
167034954ddcSFrancesco Fondelli 		return count;
167134954ddcSFrancesco Fondelli 	}
167234954ddcSFrancesco Fondelli 
167334954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_cfi")) {
167434954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
167563adc6fbSStephen Hemminger 		if (len < 0)
167634954ddcSFrancesco Fondelli 			return len;
167763adc6fbSStephen Hemminger 
167834954ddcSFrancesco Fondelli 		i += len;
167934954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
168034954ddcSFrancesco Fondelli 			pkt_dev->vlan_cfi = value;
168134954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
168234954ddcSFrancesco Fondelli 		} else {
168334954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
168434954ddcSFrancesco Fondelli 		}
168534954ddcSFrancesco Fondelli 		return count;
168634954ddcSFrancesco Fondelli 	}
168734954ddcSFrancesco Fondelli 
168834954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_id")) {
168934954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
169063adc6fbSStephen Hemminger 		if (len < 0)
169134954ddcSFrancesco Fondelli 			return len;
169263adc6fbSStephen Hemminger 
169334954ddcSFrancesco Fondelli 		i += len;
169434954ddcSFrancesco Fondelli 		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
169534954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = value;  /* turn on SVLAN */
169634954ddcSFrancesco Fondelli 
169734954ddcSFrancesco Fondelli 			if (debug)
1698f342cda7SJoe Perches 				pr_debug("SVLAN turned on\n");
169934954ddcSFrancesco Fondelli 
170034954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
1701f342cda7SJoe Perches 				pr_debug("MPLS auto turned off\n");
170234954ddcSFrancesco Fondelli 
170334954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
170434954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
170534954ddcSFrancesco Fondelli 		} else {
170634954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
170734954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
170834954ddcSFrancesco Fondelli 
170934954ddcSFrancesco Fondelli 			if (debug)
1710f342cda7SJoe Perches 				pr_debug("VLAN/SVLAN turned off\n");
171134954ddcSFrancesco Fondelli 		}
171234954ddcSFrancesco Fondelli 		return count;
171334954ddcSFrancesco Fondelli 	}
171434954ddcSFrancesco Fondelli 
171534954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_p")) {
171634954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
171763adc6fbSStephen Hemminger 		if (len < 0)
171834954ddcSFrancesco Fondelli 			return len;
171963adc6fbSStephen Hemminger 
172034954ddcSFrancesco Fondelli 		i += len;
172134954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
172234954ddcSFrancesco Fondelli 			pkt_dev->svlan_p = value;
172334954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
172434954ddcSFrancesco Fondelli 		} else {
172534954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_p must be 0-7");
172634954ddcSFrancesco Fondelli 		}
172734954ddcSFrancesco Fondelli 		return count;
172834954ddcSFrancesco Fondelli 	}
172934954ddcSFrancesco Fondelli 
173034954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_cfi")) {
173134954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
173263adc6fbSStephen Hemminger 		if (len < 0)
173334954ddcSFrancesco Fondelli 			return len;
173463adc6fbSStephen Hemminger 
173534954ddcSFrancesco Fondelli 		i += len;
173634954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
173734954ddcSFrancesco Fondelli 			pkt_dev->svlan_cfi = value;
173834954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
173934954ddcSFrancesco Fondelli 		} else {
174034954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
174134954ddcSFrancesco Fondelli 		}
1742ca6549afSSteven Whitehouse 		return count;
1743ca6549afSSteven Whitehouse 	}
1744ca6549afSSteven Whitehouse 
17451ca7768cSFrancesco Fondelli 	if (!strcmp(name, "tos")) {
17461ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
17471ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
174863adc6fbSStephen Hemminger 		if (len < 0)
17491ca7768cSFrancesco Fondelli 			return len;
175063adc6fbSStephen Hemminger 
17511ca7768cSFrancesco Fondelli 		i += len;
17521ca7768cSFrancesco Fondelli 		if (len == 2) {
17531ca7768cSFrancesco Fondelli 			pkt_dev->tos = tmp_value;
17541ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
17551ca7768cSFrancesco Fondelli 		} else {
17561ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: tos must be 00-ff");
17571ca7768cSFrancesco Fondelli 		}
17581ca7768cSFrancesco Fondelli 		return count;
17591ca7768cSFrancesco Fondelli 	}
17601ca7768cSFrancesco Fondelli 
17611ca7768cSFrancesco Fondelli 	if (!strcmp(name, "traffic_class")) {
17621ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
17631ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
176463adc6fbSStephen Hemminger 		if (len < 0)
17651ca7768cSFrancesco Fondelli 			return len;
176663adc6fbSStephen Hemminger 
17671ca7768cSFrancesco Fondelli 		i += len;
17681ca7768cSFrancesco Fondelli 		if (len == 2) {
17691ca7768cSFrancesco Fondelli 			pkt_dev->traffic_class = tmp_value;
17701ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
17711ca7768cSFrancesco Fondelli 		} else {
17721ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
17731ca7768cSFrancesco Fondelli 		}
17741ca7768cSFrancesco Fondelli 		return count;
17751ca7768cSFrancesco Fondelli 	}
17761ca7768cSFrancesco Fondelli 
17779e50e3acSJohn Fastabend 	if (!strcmp(name, "skb_priority")) {
17789e50e3acSJohn Fastabend 		len = num_arg(&user_buffer[i], 9, &value);
17799e50e3acSJohn Fastabend 		if (len < 0)
17809e50e3acSJohn Fastabend 			return len;
17819e50e3acSJohn Fastabend 
17829e50e3acSJohn Fastabend 		i += len;
17839e50e3acSJohn Fastabend 		pkt_dev->skb_priority = value;
17849e50e3acSJohn Fastabend 		sprintf(pg_result, "OK: skb_priority=%i",
17859e50e3acSJohn Fastabend 			pkt_dev->skb_priority);
17869e50e3acSJohn Fastabend 		return count;
17879e50e3acSJohn Fastabend 	}
17889e50e3acSJohn Fastabend 
17891da177e4SLinus Torvalds 	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
17901da177e4SLinus Torvalds 	return -EINVAL;
17911da177e4SLinus Torvalds }
17921da177e4SLinus Torvalds 
1793d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file)
17941da177e4SLinus Torvalds {
1795d9dda78bSAl Viro 	return single_open(file, pktgen_if_show, PDE_DATA(inode));
17961da177e4SLinus Torvalds }
17971da177e4SLinus Torvalds 
17989a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = {
1799d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
1800d50a6b56SStephen Hemminger 	.open    = pktgen_if_open,
1801d50a6b56SStephen Hemminger 	.read    = seq_read,
1802d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1803d50a6b56SStephen Hemminger 	.write   = pktgen_if_write,
1804d50a6b56SStephen Hemminger 	.release = single_release,
1805d50a6b56SStephen Hemminger };
1806d50a6b56SStephen Hemminger 
1807d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v)
1808d50a6b56SStephen Hemminger {
1809d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1810648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
1811d50a6b56SStephen Hemminger 
1812d50a6b56SStephen Hemminger 	BUG_ON(!t);
1813d50a6b56SStephen Hemminger 
181497dc48e2SThomas Graf 	seq_puts(seq, "Running: ");
18151da177e4SLinus Torvalds 
18168788370aSJesper Dangaard Brouer 	rcu_read_lock();
18178788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
18181da177e4SLinus Torvalds 		if (pkt_dev->running)
1819593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
18201da177e4SLinus Torvalds 
182197dc48e2SThomas Graf 	seq_puts(seq, "\nStopped: ");
18221da177e4SLinus Torvalds 
18238788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
18241da177e4SLinus Torvalds 		if (!pkt_dev->running)
1825593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
18261da177e4SLinus Torvalds 
18271da177e4SLinus Torvalds 	if (t->result[0])
1828d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: %s\n", t->result);
18291da177e4SLinus Torvalds 	else
183097dc48e2SThomas Graf 		seq_puts(seq, "\nResult: NA\n");
18311da177e4SLinus Torvalds 
18328788370aSJesper Dangaard Brouer 	rcu_read_unlock();
18331da177e4SLinus Torvalds 
1834d50a6b56SStephen Hemminger 	return 0;
18351da177e4SLinus Torvalds }
18361da177e4SLinus Torvalds 
1837d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file,
1838d50a6b56SStephen Hemminger 				   const char __user * user_buffer,
1839d50a6b56SStephen Hemminger 				   size_t count, loff_t * offset)
18401da177e4SLinus Torvalds {
18418a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
1842d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1843d6182223SPaul Gortmaker 	int i, max, len, ret;
18441da177e4SLinus Torvalds 	char name[40];
18451da177e4SLinus Torvalds 	char *pg_result;
18461da177e4SLinus Torvalds 
18471da177e4SLinus Torvalds 	if (count < 1) {
18481da177e4SLinus Torvalds 		//      sprintf(pg_result, "Wrong command format");
18491da177e4SLinus Torvalds 		return -EINVAL;
18501da177e4SLinus Torvalds 	}
18511da177e4SLinus Torvalds 
1852d6182223SPaul Gortmaker 	max = count;
1853d6182223SPaul Gortmaker 	len = count_trail_chars(user_buffer, max);
18541da177e4SLinus Torvalds 	if (len < 0)
18551da177e4SLinus Torvalds 		return len;
18561da177e4SLinus Torvalds 
1857d6182223SPaul Gortmaker 	i = len;
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds 	/* Read variable name */
18601da177e4SLinus Torvalds 
18611da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
18621da177e4SLinus Torvalds 	if (len < 0)
18631da177e4SLinus Torvalds 		return len;
18641da177e4SLinus Torvalds 
18651da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
18661da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
18671da177e4SLinus Torvalds 		return -EFAULT;
18681da177e4SLinus Torvalds 	i += len;
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds 	max = count - i;
18711da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
18721da177e4SLinus Torvalds 	if (len < 0)
18731da177e4SLinus Torvalds 		return len;
18741da177e4SLinus Torvalds 
18751da177e4SLinus Torvalds 	i += len;
18761da177e4SLinus Torvalds 
18771da177e4SLinus Torvalds 	if (debug)
1878f342cda7SJoe Perches 		pr_debug("t=%s, count=%lu\n", name, (unsigned long)count);
18791da177e4SLinus Torvalds 
18801da177e4SLinus Torvalds 	if (!t) {
1881f9467eaeSJoe Perches 		pr_err("ERROR: No thread\n");
18821da177e4SLinus Torvalds 		ret = -EINVAL;
18831da177e4SLinus Torvalds 		goto out;
18841da177e4SLinus Torvalds 	}
18851da177e4SLinus Torvalds 
18861da177e4SLinus Torvalds 	pg_result = &(t->result[0]);
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds 	if (!strcmp(name, "add_device")) {
18891da177e4SLinus Torvalds 		char f[32];
18901da177e4SLinus Torvalds 		memset(f, 0, 32);
18911da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
18921da177e4SLinus Torvalds 		if (len < 0) {
18931da177e4SLinus Torvalds 			ret = len;
18941da177e4SLinus Torvalds 			goto out;
18951da177e4SLinus Torvalds 		}
18961da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
18971da177e4SLinus Torvalds 			return -EFAULT;
18981da177e4SLinus Torvalds 		i += len;
18996146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
1900604dfd6eSCong Wang 		ret = pktgen_add_device(t, f);
19016146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1902604dfd6eSCong Wang 		if (!ret) {
19031da177e4SLinus Torvalds 			ret = count;
19041da177e4SLinus Torvalds 			sprintf(pg_result, "OK: add_device=%s", f);
1905604dfd6eSCong Wang 		} else
1906604dfd6eSCong Wang 			sprintf(pg_result, "ERROR: can not add device %s", f);
19071da177e4SLinus Torvalds 		goto out;
19081da177e4SLinus Torvalds 	}
19091da177e4SLinus Torvalds 
19101da177e4SLinus Torvalds 	if (!strcmp(name, "rem_device_all")) {
19116146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
191295ed63f7SArthur Kepner 		t->control |= T_REMDEVALL;
19136146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1914121caf57SNishanth Aravamudan 		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
19151da177e4SLinus Torvalds 		ret = count;
19161da177e4SLinus Torvalds 		sprintf(pg_result, "OK: rem_device_all");
19171da177e4SLinus Torvalds 		goto out;
19181da177e4SLinus Torvalds 	}
19191da177e4SLinus Torvalds 
19201da177e4SLinus Torvalds 	if (!strcmp(name, "max_before_softirq")) {
1921b163911fSRobert Olsson 		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
19221da177e4SLinus Torvalds 		ret = count;
19231da177e4SLinus Torvalds 		goto out;
19241da177e4SLinus Torvalds 	}
19251da177e4SLinus Torvalds 
19261da177e4SLinus Torvalds 	ret = -EINVAL;
19271da177e4SLinus Torvalds out:
19281da177e4SLinus Torvalds 	return ret;
19291da177e4SLinus Torvalds }
19301da177e4SLinus Torvalds 
1931d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file)
19321da177e4SLinus Torvalds {
1933d9dda78bSAl Viro 	return single_open(file, pktgen_thread_show, PDE_DATA(inode));
19341da177e4SLinus Torvalds }
19351da177e4SLinus Torvalds 
19369a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = {
1937d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
1938d50a6b56SStephen Hemminger 	.open    = pktgen_thread_open,
1939d50a6b56SStephen Hemminger 	.read    = seq_read,
1940d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1941d50a6b56SStephen Hemminger 	.write   = pktgen_thread_write,
1942d50a6b56SStephen Hemminger 	.release = single_release,
1943d50a6b56SStephen Hemminger };
19441da177e4SLinus Torvalds 
19451da177e4SLinus Torvalds /* Think find or remove for NN */
19464e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn,
19474e58a027SCong Wang 					      const char *ifname, int remove)
19481da177e4SLinus Torvalds {
19491da177e4SLinus Torvalds 	struct pktgen_thread *t;
19501da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
19513e984840SEric Dumazet 	bool exact = (remove == FIND);
19521da177e4SLinus Torvalds 
19534e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
19543e984840SEric Dumazet 		pkt_dev = pktgen_find_dev(t, ifname, exact);
19551da177e4SLinus Torvalds 		if (pkt_dev) {
19561da177e4SLinus Torvalds 			if (remove) {
195795ed63f7SArthur Kepner 				pkt_dev->removal_mark = 1;
195895ed63f7SArthur Kepner 				t->control |= T_REMDEV;
19591da177e4SLinus Torvalds 			}
19601da177e4SLinus Torvalds 			break;
19611da177e4SLinus Torvalds 		}
19621da177e4SLinus Torvalds 	}
19631da177e4SLinus Torvalds 	return pkt_dev;
19641da177e4SLinus Torvalds }
19651da177e4SLinus Torvalds 
196695ed63f7SArthur Kepner /*
196795ed63f7SArthur Kepner  * mark a device for removal
196895ed63f7SArthur Kepner  */
19694e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname)
19701da177e4SLinus Torvalds {
19711da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
197295ed63f7SArthur Kepner 	const int max_tries = 10, msec_per_try = 125;
197395ed63f7SArthur Kepner 	int i = 0;
197495ed63f7SArthur Kepner 
19756146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
1976f9467eaeSJoe Perches 	pr_debug("%s: marking %s for removal\n", __func__, ifname);
197795ed63f7SArthur Kepner 
197895ed63f7SArthur Kepner 	while (1) {
197995ed63f7SArthur Kepner 
19804e58a027SCong Wang 		pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE);
1981222f1806SLuiz Capitulino 		if (pkt_dev == NULL)
1982222f1806SLuiz Capitulino 			break;	/* success */
198395ed63f7SArthur Kepner 
19846146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1985f9467eaeSJoe Perches 		pr_debug("%s: waiting for %s to disappear....\n",
1986f9467eaeSJoe Perches 			 __func__, ifname);
198795ed63f7SArthur Kepner 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
19886146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
198995ed63f7SArthur Kepner 
199095ed63f7SArthur Kepner 		if (++i >= max_tries) {
1991f9467eaeSJoe Perches 			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
1992f9467eaeSJoe Perches 			       __func__, msec_per_try * i, ifname);
199395ed63f7SArthur Kepner 			break;
199495ed63f7SArthur Kepner 		}
199595ed63f7SArthur Kepner 
199695ed63f7SArthur Kepner 	}
199795ed63f7SArthur Kepner 
19986146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
199939df232fSStephen Hemminger }
200095ed63f7SArthur Kepner 
20014e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev)
200239df232fSStephen Hemminger {
200339df232fSStephen Hemminger 	struct pktgen_thread *t;
200439df232fSStephen Hemminger 
20054e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
200639df232fSStephen Hemminger 		struct pktgen_dev *pkt_dev;
200739df232fSStephen Hemminger 
20088788370aSJesper Dangaard Brouer 		rcu_read_lock();
20098788370aSJesper Dangaard Brouer 		list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
201039df232fSStephen Hemminger 			if (pkt_dev->odev != dev)
201139df232fSStephen Hemminger 				continue;
201239df232fSStephen Hemminger 
2013a8ca16eaSDavid Howells 			proc_remove(pkt_dev->entry);
201439df232fSStephen Hemminger 
20152975315bSAlexey Dobriyan 			pkt_dev->entry = proc_create_data(dev->name, 0600,
20164e58a027SCong Wang 							  pn->proc_dir,
20172975315bSAlexey Dobriyan 							  &pktgen_if_fops,
20182975315bSAlexey Dobriyan 							  pkt_dev);
201939df232fSStephen Hemminger 			if (!pkt_dev->entry)
2020f9467eaeSJoe Perches 				pr_err("can't move proc entry for '%s'\n",
2021f9467eaeSJoe Perches 				       dev->name);
202239df232fSStephen Hemminger 			break;
202339df232fSStephen Hemminger 		}
20248788370aSJesper Dangaard Brouer 		rcu_read_unlock();
202539df232fSStephen Hemminger 	}
20261da177e4SLinus Torvalds }
20271da177e4SLinus Torvalds 
2028222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused,
2029222f1806SLuiz Capitulino 			       unsigned long event, void *ptr)
20301da177e4SLinus Torvalds {
2031351638e7SJiri Pirko 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
20324e58a027SCong Wang 	struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id);
20331da177e4SLinus Torvalds 
20344e58a027SCong Wang 	if (pn->pktgen_exiting)
2035e9dc8653SEric W. Biederman 		return NOTIFY_DONE;
2036e9dc8653SEric W. Biederman 
20371da177e4SLinus Torvalds 	/* It is OK that we do not hold the group lock right now,
20381da177e4SLinus Torvalds 	 * as we run under the RTNL lock.
20391da177e4SLinus Torvalds 	 */
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 	switch (event) {
204239df232fSStephen Hemminger 	case NETDEV_CHANGENAME:
20434e58a027SCong Wang 		pktgen_change_name(pn, dev);
20441da177e4SLinus Torvalds 		break;
20451da177e4SLinus Torvalds 
20461da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
20474e58a027SCong Wang 		pktgen_mark_device(pn, dev->name);
20481da177e4SLinus Torvalds 		break;
20493ff50b79SStephen Hemminger 	}
20501da177e4SLinus Torvalds 
20511da177e4SLinus Torvalds 	return NOTIFY_DONE;
20521da177e4SLinus Torvalds }
20531da177e4SLinus Torvalds 
20544e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn,
20554e58a027SCong Wang 						 struct pktgen_dev *pkt_dev,
205663adc6fbSStephen Hemminger 						 const char *ifname)
2057e6fce5b9SRobert Olsson {
2058e6fce5b9SRobert Olsson 	char b[IFNAMSIZ+5];
2059d6182223SPaul Gortmaker 	int i;
2060e6fce5b9SRobert Olsson 
2061e6fce5b9SRobert Olsson 	for (i = 0; ifname[i] != '@'; i++) {
2062e6fce5b9SRobert Olsson 		if (i == IFNAMSIZ)
2063e6fce5b9SRobert Olsson 			break;
2064e6fce5b9SRobert Olsson 
2065e6fce5b9SRobert Olsson 		b[i] = ifname[i];
2066e6fce5b9SRobert Olsson 	}
2067e6fce5b9SRobert Olsson 	b[i] = 0;
2068e6fce5b9SRobert Olsson 
20694e58a027SCong Wang 	return dev_get_by_name(pn->net, b);
2070e6fce5b9SRobert Olsson }
2071e6fce5b9SRobert Olsson 
2072e6fce5b9SRobert Olsson 
20731da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */
20741da177e4SLinus Torvalds 
20754e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn,
20764e58a027SCong Wang 			    struct pktgen_dev *pkt_dev, const char *ifname)
2077222f1806SLuiz Capitulino {
20781da177e4SLinus Torvalds 	struct net_device *odev;
207939df232fSStephen Hemminger 	int err;
20801da177e4SLinus Torvalds 
20811da177e4SLinus Torvalds 	/* Clean old setups */
20821da177e4SLinus Torvalds 	if (pkt_dev->odev) {
20831da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
20841da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
20851da177e4SLinus Torvalds 	}
20861da177e4SLinus Torvalds 
20874e58a027SCong Wang 	odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname);
20881da177e4SLinus Torvalds 	if (!odev) {
2089f9467eaeSJoe Perches 		pr_err("no such netdevice: \"%s\"\n", ifname);
209039df232fSStephen Hemminger 		return -ENODEV;
20911da177e4SLinus Torvalds 	}
209239df232fSStephen Hemminger 
20931da177e4SLinus Torvalds 	if (odev->type != ARPHRD_ETHER) {
2094f9467eaeSJoe Perches 		pr_err("not an ethernet device: \"%s\"\n", ifname);
209539df232fSStephen Hemminger 		err = -EINVAL;
209639df232fSStephen Hemminger 	} else if (!netif_running(odev)) {
2097f9467eaeSJoe Perches 		pr_err("device is down: \"%s\"\n", ifname);
209839df232fSStephen Hemminger 		err = -ENETDOWN;
209939df232fSStephen Hemminger 	} else {
21001da177e4SLinus Torvalds 		pkt_dev->odev = odev;
210139df232fSStephen Hemminger 		return 0;
210239df232fSStephen Hemminger 	}
21031da177e4SLinus Torvalds 
21041da177e4SLinus Torvalds 	dev_put(odev);
210539df232fSStephen Hemminger 	return err;
21061da177e4SLinus Torvalds }
21071da177e4SLinus Torvalds 
21081da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev
21091da177e4SLinus Torvalds  * structure to have the right information to create/send packets
21101da177e4SLinus Torvalds  */
21111da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
21121da177e4SLinus Torvalds {
211364c00d81SAndrew Gallatin 	int ntxq;
211464c00d81SAndrew Gallatin 
21151da177e4SLinus Torvalds 	if (!pkt_dev->odev) {
2116f9467eaeSJoe Perches 		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
2117222f1806SLuiz Capitulino 		sprintf(pkt_dev->result,
2118222f1806SLuiz Capitulino 			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
21191da177e4SLinus Torvalds 		return;
21201da177e4SLinus Torvalds 	}
21211da177e4SLinus Torvalds 
212264c00d81SAndrew Gallatin 	/* make sure that we don't pick a non-existing transmit queue */
212364c00d81SAndrew Gallatin 	ntxq = pkt_dev->odev->real_num_tx_queues;
2124bfdbc0acSRobert Olsson 
212564c00d81SAndrew Gallatin 	if (ntxq <= pkt_dev->queue_map_min) {
2126294a0b7fSJoe Perches 		pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
212788271660SJesse Brandeburg 			pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
2128593f63b0SEric Dumazet 			pkt_dev->odevname);
212926e29eedSDan Carpenter 		pkt_dev->queue_map_min = (ntxq ?: 1) - 1;
213064c00d81SAndrew Gallatin 	}
213188271660SJesse Brandeburg 	if (pkt_dev->queue_map_max >= ntxq) {
2132294a0b7fSJoe Perches 		pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
213388271660SJesse Brandeburg 			pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
2134593f63b0SEric Dumazet 			pkt_dev->odevname);
213526e29eedSDan Carpenter 		pkt_dev->queue_map_max = (ntxq ?: 1) - 1;
213664c00d81SAndrew Gallatin 	}
213764c00d81SAndrew Gallatin 
21381da177e4SLinus Torvalds 	/* Default to the interface's mac if not explicitly set. */
21391da177e4SLinus Torvalds 
2140f404e9a6SKris Katterjohn 	if (is_zero_ether_addr(pkt_dev->src_mac))
21419ea08b12SJoe Perches 		ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr);
21421da177e4SLinus Torvalds 
21431da177e4SLinus Torvalds 	/* Set up Dest MAC */
21449ea08b12SJoe Perches 	ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac);
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
21474c139b8cSAmerigo Wang 		int i, set = 0, err = 1;
21484c139b8cSAmerigo Wang 		struct inet6_dev *idev;
21494c139b8cSAmerigo Wang 
215068bf9f0bSAmerigo Wang 		if (pkt_dev->min_pkt_size == 0) {
215168bf9f0bSAmerigo Wang 			pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr)
215268bf9f0bSAmerigo Wang 						+ sizeof(struct udphdr)
215368bf9f0bSAmerigo Wang 						+ sizeof(struct pktgen_hdr)
215468bf9f0bSAmerigo Wang 						+ pkt_dev->pkt_overhead;
215568bf9f0bSAmerigo Wang 		}
215668bf9f0bSAmerigo Wang 
21571da177e4SLinus Torvalds 		for (i = 0; i < IN6_ADDR_HSIZE; i++)
21581da177e4SLinus Torvalds 			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
21591da177e4SLinus Torvalds 				set = 1;
21601da177e4SLinus Torvalds 				break;
21611da177e4SLinus Torvalds 			}
21621da177e4SLinus Torvalds 
21631da177e4SLinus Torvalds 		if (!set) {
21641da177e4SLinus Torvalds 
21651da177e4SLinus Torvalds 			/*
21661da177e4SLinus Torvalds 			 * Use linklevel address if unconfigured.
21671da177e4SLinus Torvalds 			 *
21681da177e4SLinus Torvalds 			 * use ipv6_get_lladdr if/when it's get exported
21691da177e4SLinus Torvalds 			 */
21701da177e4SLinus Torvalds 
21718814c4b5SYOSHIFUJI Hideaki 			rcu_read_lock();
217263adc6fbSStephen Hemminger 			idev = __in6_dev_get(pkt_dev->odev);
217363adc6fbSStephen Hemminger 			if (idev) {
21741da177e4SLinus Torvalds 				struct inet6_ifaddr *ifp;
21751da177e4SLinus Torvalds 
21761da177e4SLinus Torvalds 				read_lock_bh(&idev->lock);
21774c139b8cSAmerigo Wang 				list_for_each_entry(ifp, &idev->addr_list, if_list) {
21784c139b8cSAmerigo Wang 					if ((ifp->scope & IFA_LINK) &&
2179f64f9e71SJoe Perches 					    !(ifp->flags & IFA_F_TENTATIVE)) {
21804e3fd7a0SAlexey Dobriyan 						pkt_dev->cur_in6_saddr = ifp->addr;
21811da177e4SLinus Torvalds 						err = 0;
21821da177e4SLinus Torvalds 						break;
21831da177e4SLinus Torvalds 					}
21841da177e4SLinus Torvalds 				}
21851da177e4SLinus Torvalds 				read_unlock_bh(&idev->lock);
21861da177e4SLinus Torvalds 			}
21878814c4b5SYOSHIFUJI Hideaki 			rcu_read_unlock();
2188222f1806SLuiz Capitulino 			if (err)
2189f9467eaeSJoe Perches 				pr_err("ERROR: IPv6 link address not available\n");
21901da177e4SLinus Torvalds 		}
2191222f1806SLuiz Capitulino 	} else {
219268bf9f0bSAmerigo Wang 		if (pkt_dev->min_pkt_size == 0) {
219368bf9f0bSAmerigo Wang 			pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr)
219468bf9f0bSAmerigo Wang 						+ sizeof(struct udphdr)
219568bf9f0bSAmerigo Wang 						+ sizeof(struct pktgen_hdr)
219668bf9f0bSAmerigo Wang 						+ pkt_dev->pkt_overhead;
219768bf9f0bSAmerigo Wang 		}
219868bf9f0bSAmerigo Wang 
21991da177e4SLinus Torvalds 		pkt_dev->saddr_min = 0;
22001da177e4SLinus Torvalds 		pkt_dev->saddr_max = 0;
22011da177e4SLinus Torvalds 		if (strlen(pkt_dev->src_min) == 0) {
22021da177e4SLinus Torvalds 
22031da177e4SLinus Torvalds 			struct in_device *in_dev;
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds 			rcu_read_lock();
2206e5ed6399SHerbert Xu 			in_dev = __in_dev_get_rcu(pkt_dev->odev);
22071da177e4SLinus Torvalds 			if (in_dev) {
22081da177e4SLinus Torvalds 				if (in_dev->ifa_list) {
2209222f1806SLuiz Capitulino 					pkt_dev->saddr_min =
2210222f1806SLuiz Capitulino 					    in_dev->ifa_list->ifa_address;
22111da177e4SLinus Torvalds 					pkt_dev->saddr_max = pkt_dev->saddr_min;
22121da177e4SLinus Torvalds 				}
22131da177e4SLinus Torvalds 			}
22141da177e4SLinus Torvalds 			rcu_read_unlock();
2215222f1806SLuiz Capitulino 		} else {
22161da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
22171da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
22181da177e4SLinus Torvalds 		}
22191da177e4SLinus Torvalds 
22201da177e4SLinus Torvalds 		pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
22211da177e4SLinus Torvalds 		pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
22221da177e4SLinus Torvalds 	}
22231da177e4SLinus Torvalds 	/* Initialize current values. */
222468bf9f0bSAmerigo Wang 	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
222568bf9f0bSAmerigo Wang 	if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size)
222668bf9f0bSAmerigo Wang 		pkt_dev->max_pkt_size = pkt_dev->min_pkt_size;
222768bf9f0bSAmerigo Wang 
22281da177e4SLinus Torvalds 	pkt_dev->cur_dst_mac_offset = 0;
22291da177e4SLinus Torvalds 	pkt_dev->cur_src_mac_offset = 0;
22301da177e4SLinus Torvalds 	pkt_dev->cur_saddr = pkt_dev->saddr_min;
22311da177e4SLinus Torvalds 	pkt_dev->cur_daddr = pkt_dev->daddr_min;
22321da177e4SLinus Torvalds 	pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
22331da177e4SLinus Torvalds 	pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
22341da177e4SLinus Torvalds 	pkt_dev->nflows = 0;
22351da177e4SLinus Torvalds }
22361da177e4SLinus Torvalds 
22371da177e4SLinus Torvalds 
2238fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
2239fd29cf72SStephen Hemminger {
2240ef87979cSStephen Hemminger 	ktime_t start_time, end_time;
2241417bc4b8SEric Dumazet 	s64 remaining;
22422bc481cfSStephen Hemminger 	struct hrtimer_sleeper t;
2243fd29cf72SStephen Hemminger 
22442bc481cfSStephen Hemminger 	hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
22452bc481cfSStephen Hemminger 	hrtimer_set_expires(&t.timer, spin_until);
2246fd29cf72SStephen Hemminger 
224743d28b65SDaniel Turull 	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
2248417bc4b8SEric Dumazet 	if (remaining <= 0) {
2249417bc4b8SEric Dumazet 		pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
22501da177e4SLinus Torvalds 		return;
2251417bc4b8SEric Dumazet 	}
22522bc481cfSStephen Hemminger 
2253398f382cSDaniel Borkmann 	start_time = ktime_get();
225433136d12SEric Dumazet 	if (remaining < 100000) {
225533136d12SEric Dumazet 		/* for small delays (<100us), just loop until limit is reached */
225633136d12SEric Dumazet 		do {
2257398f382cSDaniel Borkmann 			end_time = ktime_get();
2258398f382cSDaniel Borkmann 		} while (ktime_compare(end_time, spin_until) < 0);
225933136d12SEric Dumazet 	} else {
22602bc481cfSStephen Hemminger 		/* see do_nanosleep */
22612bc481cfSStephen Hemminger 		hrtimer_init_sleeper(&t, current);
22622bc481cfSStephen Hemminger 		do {
22632bc481cfSStephen Hemminger 			set_current_state(TASK_INTERRUPTIBLE);
22642bc481cfSStephen Hemminger 			hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
22652bc481cfSStephen Hemminger 
22662bc481cfSStephen Hemminger 			if (likely(t.task))
22671da177e4SLinus Torvalds 				schedule();
22681da177e4SLinus Torvalds 
22692bc481cfSStephen Hemminger 			hrtimer_cancel(&t.timer);
22702bc481cfSStephen Hemminger 		} while (t.task && pkt_dev->running && !signal_pending(current));
22712bc481cfSStephen Hemminger 		__set_current_state(TASK_RUNNING);
2272398f382cSDaniel Borkmann 		end_time = ktime_get();
227333136d12SEric Dumazet 	}
2274ef87979cSStephen Hemminger 
2275ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
227607a0f0f0SDaniel Turull 	pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
22771da177e4SLinus Torvalds }
22781da177e4SLinus Torvalds 
227916dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
228016dab72fSJamal Hadi Salim {
2281879c7220SBogdan Hamciuc 	pkt_dev->pkt_overhead = LL_RESERVED_SPACE(pkt_dev->odev);
228216dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
228316dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
228416dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
228516dab72fSJamal Hadi Salim }
228616dab72fSJamal Hadi Salim 
2287648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
2288007a531bSJamal Hadi Salim {
2289648fda74SStephen Hemminger 	return !!(pkt_dev->flows[flow].flags & F_INIT);
2290007a531bSJamal Hadi Salim }
2291007a531bSJamal Hadi Salim 
2292007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev)
2293007a531bSJamal Hadi Salim {
2294007a531bSJamal Hadi Salim 	int flow = pkt_dev->curfl;
2295007a531bSJamal Hadi Salim 
2296007a531bSJamal Hadi Salim 	if (pkt_dev->flags & F_FLOW_SEQ) {
2297007a531bSJamal Hadi Salim 		if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
2298007a531bSJamal Hadi Salim 			/* reset time */
2299007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
23001211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
2301007a531bSJamal Hadi Salim 			pkt_dev->curfl += 1;
2302007a531bSJamal Hadi Salim 			if (pkt_dev->curfl >= pkt_dev->cflows)
2303007a531bSJamal Hadi Salim 				pkt_dev->curfl = 0; /*reset */
2304007a531bSJamal Hadi Salim 		}
2305007a531bSJamal Hadi Salim 	} else {
230633d7c5e5SAkinobu Mita 		flow = prandom_u32() % pkt_dev->cflows;
23071211a645SRobert Olsson 		pkt_dev->curfl = flow;
2308007a531bSJamal Hadi Salim 
23091211a645SRobert Olsson 		if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
2310007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
23111211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
23121211a645SRobert Olsson 		}
2313007a531bSJamal Hadi Salim 	}
2314007a531bSJamal Hadi Salim 
2315007a531bSJamal Hadi Salim 	return pkt_dev->curfl;
2316007a531bSJamal Hadi Salim }
2317007a531bSJamal Hadi Salim 
2318a553e4a6SJamal Hadi Salim 
2319a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2320a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else
2321a553e4a6SJamal Hadi Salim  * we go look for it ...
2322a553e4a6SJamal Hadi Salim */
2323bd55775cSJamal Hadi Salim #define DUMMY_MARK 0
2324fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
2325a553e4a6SJamal Hadi Salim {
2326a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[flow].x;
23274e58a027SCong Wang 	struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
2328a553e4a6SJamal Hadi Salim 	if (!x) {
2329c454997eSFan Du 
2330c454997eSFan Du 		if (pkt_dev->spi) {
2331c454997eSFan Du 			/* We need as quick as possible to find the right SA
2332c454997eSFan Du 			 * Searching with minimum criteria to archieve this.
2333c454997eSFan Du 			 */
2334c454997eSFan Du 			x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
2335c454997eSFan Du 		} else {
2336a553e4a6SJamal Hadi Salim 			/* slow path: we dont already have xfrm_state */
23374e58a027SCong Wang 			x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
23385447c5e4SAlexey Dobriyan 						(xfrm_address_t *)&pkt_dev->cur_daddr,
2339a553e4a6SJamal Hadi Salim 						(xfrm_address_t *)&pkt_dev->cur_saddr,
2340a553e4a6SJamal Hadi Salim 						AF_INET,
2341a553e4a6SJamal Hadi Salim 						pkt_dev->ipsmode,
2342a553e4a6SJamal Hadi Salim 						pkt_dev->ipsproto, 0);
2343c454997eSFan Du 		}
2344a553e4a6SJamal Hadi Salim 		if (x) {
2345a553e4a6SJamal Hadi Salim 			pkt_dev->flows[flow].x = x;
2346a553e4a6SJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
2347a553e4a6SJamal Hadi Salim 			pkt_dev->pkt_overhead += x->props.header_len;
2348a553e4a6SJamal Hadi Salim 		}
2349a553e4a6SJamal Hadi Salim 
2350a553e4a6SJamal Hadi Salim 	}
2351a553e4a6SJamal Hadi Salim }
2352a553e4a6SJamal Hadi Salim #endif
2353fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
2354fd2ea0a7SDavid S. Miller {
2355e6fce5b9SRobert Olsson 
2356e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
2357e6fce5b9SRobert Olsson 		pkt_dev->cur_queue_map = smp_processor_id();
2358e6fce5b9SRobert Olsson 
2359896a7cf8SEric Dumazet 	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
2360fd2ea0a7SDavid S. Miller 		__u16 t;
2361fd2ea0a7SDavid S. Miller 		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
236233d7c5e5SAkinobu Mita 			t = prandom_u32() %
2363fd2ea0a7SDavid S. Miller 				(pkt_dev->queue_map_max -
2364fd2ea0a7SDavid S. Miller 				 pkt_dev->queue_map_min + 1)
2365fd2ea0a7SDavid S. Miller 				+ pkt_dev->queue_map_min;
2366fd2ea0a7SDavid S. Miller 		} else {
2367fd2ea0a7SDavid S. Miller 			t = pkt_dev->cur_queue_map + 1;
2368fd2ea0a7SDavid S. Miller 			if (t > pkt_dev->queue_map_max)
2369fd2ea0a7SDavid S. Miller 				t = pkt_dev->queue_map_min;
2370fd2ea0a7SDavid S. Miller 		}
2371fd2ea0a7SDavid S. Miller 		pkt_dev->cur_queue_map = t;
2372fd2ea0a7SDavid S. Miller 	}
2373bfdbc0acSRobert Olsson 	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
2374fd2ea0a7SDavid S. Miller }
2375fd2ea0a7SDavid S. Miller 
23761da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values
23771da177e4SLinus Torvalds  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
23781da177e4SLinus Torvalds  */
2379222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev)
2380222f1806SLuiz Capitulino {
23811da177e4SLinus Torvalds 	__u32 imn;
23821da177e4SLinus Torvalds 	__u32 imx;
23831da177e4SLinus Torvalds 	int flow = 0;
23841da177e4SLinus Torvalds 
2385007a531bSJamal Hadi Salim 	if (pkt_dev->cflows)
2386007a531bSJamal Hadi Salim 		flow = f_pick(pkt_dev);
23871da177e4SLinus Torvalds 
23881da177e4SLinus Torvalds 	/*  Deal with source MAC */
23891da177e4SLinus Torvalds 	if (pkt_dev->src_mac_count > 1) {
23901da177e4SLinus Torvalds 		__u32 mc;
23911da177e4SLinus Torvalds 		__u32 tmp;
23921da177e4SLinus Torvalds 
23931da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACSRC_RND)
239433d7c5e5SAkinobu Mita 			mc = prandom_u32() % pkt_dev->src_mac_count;
23951da177e4SLinus Torvalds 		else {
23961da177e4SLinus Torvalds 			mc = pkt_dev->cur_src_mac_offset++;
2397ff2a79a5SRobert Olsson 			if (pkt_dev->cur_src_mac_offset >=
2398222f1806SLuiz Capitulino 			    pkt_dev->src_mac_count)
23991da177e4SLinus Torvalds 				pkt_dev->cur_src_mac_offset = 0;
24001da177e4SLinus Torvalds 		}
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds 		tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
24031da177e4SLinus Torvalds 		pkt_dev->hh[11] = tmp;
24041da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
24051da177e4SLinus Torvalds 		pkt_dev->hh[10] = tmp;
24061da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
24071da177e4SLinus Torvalds 		pkt_dev->hh[9] = tmp;
24081da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
24091da177e4SLinus Torvalds 		pkt_dev->hh[8] = tmp;
24101da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
24111da177e4SLinus Torvalds 		pkt_dev->hh[7] = tmp;
24121da177e4SLinus Torvalds 	}
24131da177e4SLinus Torvalds 
24141da177e4SLinus Torvalds 	/*  Deal with Destination MAC */
24151da177e4SLinus Torvalds 	if (pkt_dev->dst_mac_count > 1) {
24161da177e4SLinus Torvalds 		__u32 mc;
24171da177e4SLinus Torvalds 		__u32 tmp;
24181da177e4SLinus Torvalds 
24191da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACDST_RND)
242033d7c5e5SAkinobu Mita 			mc = prandom_u32() % pkt_dev->dst_mac_count;
24211da177e4SLinus Torvalds 
24221da177e4SLinus Torvalds 		else {
24231da177e4SLinus Torvalds 			mc = pkt_dev->cur_dst_mac_offset++;
2424ff2a79a5SRobert Olsson 			if (pkt_dev->cur_dst_mac_offset >=
2425222f1806SLuiz Capitulino 			    pkt_dev->dst_mac_count) {
24261da177e4SLinus Torvalds 				pkt_dev->cur_dst_mac_offset = 0;
24271da177e4SLinus Torvalds 			}
24281da177e4SLinus Torvalds 		}
24291da177e4SLinus Torvalds 
24301da177e4SLinus Torvalds 		tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
24311da177e4SLinus Torvalds 		pkt_dev->hh[5] = tmp;
24321da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
24331da177e4SLinus Torvalds 		pkt_dev->hh[4] = tmp;
24341da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
24351da177e4SLinus Torvalds 		pkt_dev->hh[3] = tmp;
24361da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
24371da177e4SLinus Torvalds 		pkt_dev->hh[2] = tmp;
24381da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
24391da177e4SLinus Torvalds 		pkt_dev->hh[1] = tmp;
24401da177e4SLinus Torvalds 	}
24411da177e4SLinus Torvalds 
2442ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND) {
244395c96174SEric Dumazet 		unsigned int i;
2444ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
2445ca6549afSSteven Whitehouse 			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
2446ca6549afSSteven Whitehouse 				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
244733d7c5e5SAkinobu Mita 					     ((__force __be32)prandom_u32() &
2448ca6549afSSteven Whitehouse 						      htonl(0x000fffff));
2449ca6549afSSteven Whitehouse 	}
2450ca6549afSSteven Whitehouse 
245134954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
245233d7c5e5SAkinobu Mita 		pkt_dev->vlan_id = prandom_u32() & (4096 - 1);
245334954ddcSFrancesco Fondelli 	}
245434954ddcSFrancesco Fondelli 
245534954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
245633d7c5e5SAkinobu Mita 		pkt_dev->svlan_id = prandom_u32() & (4096 - 1);
245734954ddcSFrancesco Fondelli 	}
245834954ddcSFrancesco Fondelli 
24591da177e4SLinus Torvalds 	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
24601da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPSRC_RND)
246133d7c5e5SAkinobu Mita 			pkt_dev->cur_udp_src = prandom_u32() %
24625fa6fc76SStephen Hemminger 				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
24635fa6fc76SStephen Hemminger 				+ pkt_dev->udp_src_min;
24641da177e4SLinus Torvalds 
24651da177e4SLinus Torvalds 		else {
24661da177e4SLinus Torvalds 			pkt_dev->cur_udp_src++;
24671da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
24681da177e4SLinus Torvalds 				pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
24691da177e4SLinus Torvalds 		}
24701da177e4SLinus Torvalds 	}
24711da177e4SLinus Torvalds 
24721da177e4SLinus Torvalds 	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
24731da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPDST_RND) {
247433d7c5e5SAkinobu Mita 			pkt_dev->cur_udp_dst = prandom_u32() %
24755fa6fc76SStephen Hemminger 				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
24765fa6fc76SStephen Hemminger 				+ pkt_dev->udp_dst_min;
2477222f1806SLuiz Capitulino 		} else {
24781da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst++;
24791da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
24801da177e4SLinus Torvalds 				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
24811da177e4SLinus Torvalds 		}
24821da177e4SLinus Torvalds 	}
24831da177e4SLinus Torvalds 
24841da177e4SLinus Torvalds 	if (!(pkt_dev->flags & F_IPV6)) {
24851da177e4SLinus Torvalds 
248663adc6fbSStephen Hemminger 		imn = ntohl(pkt_dev->saddr_min);
248763adc6fbSStephen Hemminger 		imx = ntohl(pkt_dev->saddr_max);
248863adc6fbSStephen Hemminger 		if (imn < imx) {
24891da177e4SLinus Torvalds 			__u32 t;
24901da177e4SLinus Torvalds 			if (pkt_dev->flags & F_IPSRC_RND)
249133d7c5e5SAkinobu Mita 				t = prandom_u32() % (imx - imn) + imn;
24921da177e4SLinus Torvalds 			else {
24931da177e4SLinus Torvalds 				t = ntohl(pkt_dev->cur_saddr);
24941da177e4SLinus Torvalds 				t++;
249563adc6fbSStephen Hemminger 				if (t > imx)
24961da177e4SLinus Torvalds 					t = imn;
249763adc6fbSStephen Hemminger 
24981da177e4SLinus Torvalds 			}
24991da177e4SLinus Torvalds 			pkt_dev->cur_saddr = htonl(t);
25001da177e4SLinus Torvalds 		}
25011da177e4SLinus Torvalds 
2502007a531bSJamal Hadi Salim 		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
25031da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
25041da177e4SLinus Torvalds 		} else {
2505252e3346SAl Viro 			imn = ntohl(pkt_dev->daddr_min);
2506252e3346SAl Viro 			imx = ntohl(pkt_dev->daddr_max);
2507252e3346SAl Viro 			if (imn < imx) {
25081da177e4SLinus Torvalds 				__u32 t;
2509252e3346SAl Viro 				__be32 s;
25101da177e4SLinus Torvalds 				if (pkt_dev->flags & F_IPDST_RND) {
25111da177e4SLinus Torvalds 
251270e3ba72SAkinobu Mita 					do {
251333d7c5e5SAkinobu Mita 						t = prandom_u32() %
251433d7c5e5SAkinobu Mita 							(imx - imn) + imn;
2515252e3346SAl Viro 						s = htonl(t);
251670e3ba72SAkinobu Mita 					} while (ipv4_is_loopback(s) ||
251770e3ba72SAkinobu Mita 						ipv4_is_multicast(s) ||
251870e3ba72SAkinobu Mita 						ipv4_is_lbcast(s) ||
251970e3ba72SAkinobu Mita 						ipv4_is_zeronet(s) ||
252070e3ba72SAkinobu Mita 						ipv4_is_local_multicast(s));
2521252e3346SAl Viro 					pkt_dev->cur_daddr = s;
2522252e3346SAl Viro 				} else {
25231da177e4SLinus Torvalds 					t = ntohl(pkt_dev->cur_daddr);
25241da177e4SLinus Torvalds 					t++;
25251da177e4SLinus Torvalds 					if (t > imx) {
25261da177e4SLinus Torvalds 						t = imn;
25271da177e4SLinus Torvalds 					}
25281da177e4SLinus Torvalds 					pkt_dev->cur_daddr = htonl(t);
25291da177e4SLinus Torvalds 				}
25301da177e4SLinus Torvalds 			}
25311da177e4SLinus Torvalds 			if (pkt_dev->cflows) {
2532007a531bSJamal Hadi Salim 				pkt_dev->flows[flow].flags |= F_INIT;
2533222f1806SLuiz Capitulino 				pkt_dev->flows[flow].cur_daddr =
2534222f1806SLuiz Capitulino 				    pkt_dev->cur_daddr;
2535a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2536a553e4a6SJamal Hadi Salim 				if (pkt_dev->flags & F_IPSEC_ON)
2537a553e4a6SJamal Hadi Salim 					get_ipsec_sa(pkt_dev, flow);
2538a553e4a6SJamal Hadi Salim #endif
25391da177e4SLinus Torvalds 				pkt_dev->nflows++;
25401da177e4SLinus Torvalds 			}
25411da177e4SLinus Torvalds 		}
2542222f1806SLuiz Capitulino 	} else {		/* IPV6 * */
2543222f1806SLuiz Capitulino 
254406e30411SJoe Perches 		if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) {
25451da177e4SLinus Torvalds 			int i;
25461da177e4SLinus Torvalds 
25471da177e4SLinus Torvalds 			/* Only random destinations yet */
25481da177e4SLinus Torvalds 
25491da177e4SLinus Torvalds 			for (i = 0; i < 4; i++) {
25501da177e4SLinus Torvalds 				pkt_dev->cur_in6_daddr.s6_addr32[i] =
255133d7c5e5SAkinobu Mita 				    (((__force __be32)prandom_u32() |
25521da177e4SLinus Torvalds 				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
25531da177e4SLinus Torvalds 				     pkt_dev->max_in6_daddr.s6_addr32[i]);
25541da177e4SLinus Torvalds 			}
25551da177e4SLinus Torvalds 		}
25561da177e4SLinus Torvalds 	}
25571da177e4SLinus Torvalds 
25581da177e4SLinus Torvalds 	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
25591da177e4SLinus Torvalds 		__u32 t;
25601da177e4SLinus Torvalds 		if (pkt_dev->flags & F_TXSIZE_RND) {
256133d7c5e5SAkinobu Mita 			t = prandom_u32() %
25625fa6fc76SStephen Hemminger 				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
25635fa6fc76SStephen Hemminger 				+ pkt_dev->min_pkt_size;
2564222f1806SLuiz Capitulino 		} else {
25651da177e4SLinus Torvalds 			t = pkt_dev->cur_pkt_size + 1;
25661da177e4SLinus Torvalds 			if (t > pkt_dev->max_pkt_size)
25671da177e4SLinus Torvalds 				t = pkt_dev->min_pkt_size;
25681da177e4SLinus Torvalds 		}
25691da177e4SLinus Torvalds 		pkt_dev->cur_pkt_size = t;
25701da177e4SLinus Torvalds 	}
25711da177e4SLinus Torvalds 
2572fd2ea0a7SDavid S. Miller 	set_cur_queue_map(pkt_dev);
257345b270f8SRobert Olsson 
25741da177e4SLinus Torvalds 	pkt_dev->flows[flow].count++;
25751da177e4SLinus Torvalds }
25761da177e4SLinus Torvalds 
2577a553e4a6SJamal Hadi Salim 
2578a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
25795537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
2580cf93d47eSFan Du 
2581cf93d47eSFan Du 	[RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
2582cf93d47eSFan Du };
2583cf93d47eSFan Du 
2584a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
2585a553e4a6SJamal Hadi Salim {
2586a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2587a553e4a6SJamal Hadi Salim 	int err = 0;
25886de9ace4SFan Du 	struct net *net = dev_net(pkt_dev->odev);
2589a553e4a6SJamal Hadi Salim 
2590a553e4a6SJamal Hadi Salim 	if (!x)
2591a553e4a6SJamal Hadi Salim 		return 0;
2592a553e4a6SJamal Hadi Salim 	/* XXX: we dont support tunnel mode for now until
2593a553e4a6SJamal Hadi Salim 	 * we resolve the dst issue */
2594cf93d47eSFan Du 	if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
2595a553e4a6SJamal Hadi Salim 		return 0;
2596a553e4a6SJamal Hadi Salim 
2597cf93d47eSFan Du 	/* But when user specify an valid SPI, transformation
2598cf93d47eSFan Du 	 * supports both transport/tunnel mode + ESP/AH type.
2599cf93d47eSFan Du 	 */
2600cf93d47eSFan Du 	if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
2601cf93d47eSFan Du 		skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF;
2602cf93d47eSFan Du 
2603cf93d47eSFan Du 	rcu_read_lock_bh();
260413996378SHerbert Xu 	err = x->outer_mode->output(x, skb);
2605cf93d47eSFan Du 	rcu_read_unlock_bh();
26066de9ace4SFan Du 	if (err) {
26076de9ace4SFan Du 		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
2608a553e4a6SJamal Hadi Salim 		goto error;
26096de9ace4SFan Du 	}
2610a553e4a6SJamal Hadi Salim 	err = x->type->output(x, skb);
26116de9ace4SFan Du 	if (err) {
26126de9ace4SFan Du 		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
2613a553e4a6SJamal Hadi Salim 		goto error;
26146de9ace4SFan Du 	}
26150af0a413SFan Du 	spin_lock_bh(&x->lock);
2616a553e4a6SJamal Hadi Salim 	x->curlft.bytes += skb->len;
2617a553e4a6SJamal Hadi Salim 	x->curlft.packets++;
26180af0a413SFan Du 	spin_unlock_bh(&x->lock);
2619a553e4a6SJamal Hadi Salim error:
2620a553e4a6SJamal Hadi Salim 	return err;
2621a553e4a6SJamal Hadi Salim }
2622a553e4a6SJamal Hadi Salim 
2623475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev)
2624a553e4a6SJamal Hadi Salim {
2625a553e4a6SJamal Hadi Salim 	if (pkt_dev->cflows) {
2626a553e4a6SJamal Hadi Salim 		/* let go of the SAs if we have them */
2627d6182223SPaul Gortmaker 		int i;
2628d6182223SPaul Gortmaker 		for (i = 0; i < pkt_dev->cflows; i++) {
2629a553e4a6SJamal Hadi Salim 			struct xfrm_state *x = pkt_dev->flows[i].x;
2630a553e4a6SJamal Hadi Salim 			if (x) {
2631a553e4a6SJamal Hadi Salim 				xfrm_state_put(x);
2632a553e4a6SJamal Hadi Salim 				pkt_dev->flows[i].x = NULL;
2633a553e4a6SJamal Hadi Salim 			}
2634a553e4a6SJamal Hadi Salim 		}
2635a553e4a6SJamal Hadi Salim 	}
2636a553e4a6SJamal Hadi Salim }
2637a553e4a6SJamal Hadi Salim 
2638475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev,
2639a553e4a6SJamal Hadi Salim 			      struct sk_buff *skb, __be16 protocol)
2640a553e4a6SJamal Hadi Salim {
2641a553e4a6SJamal Hadi Salim 	if (pkt_dev->flags & F_IPSEC_ON) {
2642a553e4a6SJamal Hadi Salim 		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2643a553e4a6SJamal Hadi Salim 		int nhead = 0;
2644a553e4a6SJamal Hadi Salim 		if (x) {
2645d4969581SEric Dumazet 			struct ethhdr *eth;
26463868204dSfan.du 			struct iphdr *iph;
2647d4969581SEric Dumazet 			int ret;
26483868204dSfan.du 
2649a553e4a6SJamal Hadi Salim 			nhead = x->props.header_len - skb_headroom(skb);
2650a553e4a6SJamal Hadi Salim 			if (nhead > 0) {
2651a553e4a6SJamal Hadi Salim 				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
2652a553e4a6SJamal Hadi Salim 				if (ret < 0) {
2653f9467eaeSJoe Perches 					pr_err("Error expanding ipsec packet %d\n",
2654f9467eaeSJoe Perches 					       ret);
2655b4bb4ac8SIlpo Järvinen 					goto err;
2656a553e4a6SJamal Hadi Salim 				}
2657a553e4a6SJamal Hadi Salim 			}
2658a553e4a6SJamal Hadi Salim 
2659a553e4a6SJamal Hadi Salim 			/* ipsec is not expecting ll header */
2660a553e4a6SJamal Hadi Salim 			skb_pull(skb, ETH_HLEN);
2661a553e4a6SJamal Hadi Salim 			ret = pktgen_output_ipsec(skb, pkt_dev);
2662a553e4a6SJamal Hadi Salim 			if (ret) {
2663f9467eaeSJoe Perches 				pr_err("Error creating ipsec packet %d\n", ret);
2664b4bb4ac8SIlpo Järvinen 				goto err;
2665a553e4a6SJamal Hadi Salim 			}
2666a553e4a6SJamal Hadi Salim 			/* restore ll */
2667d4969581SEric Dumazet 			eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
2668d4969581SEric Dumazet 			memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN);
2669d4969581SEric Dumazet 			eth->h_proto = protocol;
26703868204dSfan.du 
26713868204dSfan.du 			/* Update IPv4 header len as well as checksum value */
26723868204dSfan.du 			iph = ip_hdr(skb);
26733868204dSfan.du 			iph->tot_len = htons(skb->len - ETH_HLEN);
26743868204dSfan.du 			ip_send_check(iph);
2675a553e4a6SJamal Hadi Salim 		}
2676a553e4a6SJamal Hadi Salim 	}
2677a553e4a6SJamal Hadi Salim 	return 1;
2678b4bb4ac8SIlpo Järvinen err:
2679b4bb4ac8SIlpo Järvinen 	kfree_skb(skb);
2680b4bb4ac8SIlpo Järvinen 	return 0;
2681a553e4a6SJamal Hadi Salim }
2682a553e4a6SJamal Hadi Salim #endif
2683a553e4a6SJamal Hadi Salim 
2684ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
2685ca6549afSSteven Whitehouse {
268695c96174SEric Dumazet 	unsigned int i;
268763adc6fbSStephen Hemminger 	for (i = 0; i < pkt_dev->nr_labels; i++)
2688ca6549afSSteven Whitehouse 		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
268963adc6fbSStephen Hemminger 
2690ca6549afSSteven Whitehouse 	mpls--;
2691ca6549afSSteven Whitehouse 	*mpls |= MPLS_STACK_BOTTOM;
2692ca6549afSSteven Whitehouse }
2693ca6549afSSteven Whitehouse 
26940f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi,
26950f37c605SAl Viro 			       unsigned int prio)
26960f37c605SAl Viro {
26970f37c605SAl Viro 	return htons(id | (cfi << 12) | (prio << 13));
26980f37c605SAl Viro }
26990f37c605SAl Viro 
270026ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
270126ad7879SEric Dumazet 				int datalen)
270226ad7879SEric Dumazet {
270326ad7879SEric Dumazet 	struct timeval timestamp;
270426ad7879SEric Dumazet 	struct pktgen_hdr *pgh;
270526ad7879SEric Dumazet 
270626ad7879SEric Dumazet 	pgh = (struct pktgen_hdr *)skb_put(skb, sizeof(*pgh));
270726ad7879SEric Dumazet 	datalen -= sizeof(*pgh);
270826ad7879SEric Dumazet 
270926ad7879SEric Dumazet 	if (pkt_dev->nfrags <= 0) {
271005aebe2eSDaniel Turull 		memset(skb_put(skb, datalen), 0, datalen);
271126ad7879SEric Dumazet 	} else {
271226ad7879SEric Dumazet 		int frags = pkt_dev->nfrags;
271326ad7879SEric Dumazet 		int i, len;
27147d36a991Samit salecha 		int frag_len;
271526ad7879SEric Dumazet 
271626ad7879SEric Dumazet 
271726ad7879SEric Dumazet 		if (frags > MAX_SKB_FRAGS)
271826ad7879SEric Dumazet 			frags = MAX_SKB_FRAGS;
271926ad7879SEric Dumazet 		len = datalen - frags * PAGE_SIZE;
272026ad7879SEric Dumazet 		if (len > 0) {
272126ad7879SEric Dumazet 			memset(skb_put(skb, len), 0, len);
272226ad7879SEric Dumazet 			datalen = frags * PAGE_SIZE;
272326ad7879SEric Dumazet 		}
272426ad7879SEric Dumazet 
272526ad7879SEric Dumazet 		i = 0;
27267d36a991Samit salecha 		frag_len = (datalen/frags) < PAGE_SIZE ?
27277d36a991Samit salecha 			   (datalen/frags) : PAGE_SIZE;
272826ad7879SEric Dumazet 		while (datalen > 0) {
272926ad7879SEric Dumazet 			if (unlikely(!pkt_dev->page)) {
273026ad7879SEric Dumazet 				int node = numa_node_id();
273126ad7879SEric Dumazet 
273226ad7879SEric Dumazet 				if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
273326ad7879SEric Dumazet 					node = pkt_dev->node;
273426ad7879SEric Dumazet 				pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
273526ad7879SEric Dumazet 				if (!pkt_dev->page)
273626ad7879SEric Dumazet 					break;
273726ad7879SEric Dumazet 			}
2738a0bec1cdSIan Campbell 			get_page(pkt_dev->page);
2739ea2ab693SIan Campbell 			skb_frag_set_page(skb, i, pkt_dev->page);
274026ad7879SEric Dumazet 			skb_shinfo(skb)->frags[i].page_offset = 0;
27417d36a991Samit salecha 			/*last fragment, fill rest of data*/
27427d36a991Samit salecha 			if (i == (frags - 1))
27439e903e08SEric Dumazet 				skb_frag_size_set(&skb_shinfo(skb)->frags[i],
27449e903e08SEric Dumazet 				    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE));
27457d36a991Samit salecha 			else
27469e903e08SEric Dumazet 				skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len);
27479e903e08SEric Dumazet 			datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
27489e903e08SEric Dumazet 			skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
27499e903e08SEric Dumazet 			skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
275026ad7879SEric Dumazet 			i++;
275126ad7879SEric Dumazet 			skb_shinfo(skb)->nr_frags = i;
275226ad7879SEric Dumazet 		}
275326ad7879SEric Dumazet 	}
275426ad7879SEric Dumazet 
275526ad7879SEric Dumazet 	/* Stamp the time, and sequence number,
275626ad7879SEric Dumazet 	 * convert them to network byte order
275726ad7879SEric Dumazet 	 */
275826ad7879SEric Dumazet 	pgh->pgh_magic = htonl(PKTGEN_MAGIC);
275926ad7879SEric Dumazet 	pgh->seq_num = htonl(pkt_dev->seq_num);
276026ad7879SEric Dumazet 
2761afb84b62SJesper Dangaard Brouer 	if (pkt_dev->flags & F_NO_TIMESTAMP) {
2762afb84b62SJesper Dangaard Brouer 		pgh->tv_sec = 0;
2763afb84b62SJesper Dangaard Brouer 		pgh->tv_usec = 0;
2764afb84b62SJesper Dangaard Brouer 	} else {
276526ad7879SEric Dumazet 		do_gettimeofday(&timestamp);
276626ad7879SEric Dumazet 		pgh->tv_sec = htonl(timestamp.tv_sec);
276726ad7879SEric Dumazet 		pgh->tv_usec = htonl(timestamp.tv_usec);
276826ad7879SEric Dumazet 	}
2769afb84b62SJesper Dangaard Brouer }
277026ad7879SEric Dumazet 
27717a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
27727a6e288dSDaniel Borkmann 					struct pktgen_dev *pkt_dev,
27737a6e288dSDaniel Borkmann 					unsigned int extralen)
27747a6e288dSDaniel Borkmann {
27757a6e288dSDaniel Borkmann 	struct sk_buff *skb = NULL;
27767a6e288dSDaniel Borkmann 	unsigned int size = pkt_dev->cur_pkt_size + 64 + extralen +
27777a6e288dSDaniel Borkmann 			    pkt_dev->pkt_overhead;
27787a6e288dSDaniel Borkmann 
27797a6e288dSDaniel Borkmann 	if (pkt_dev->flags & F_NODE) {
27807a6e288dSDaniel Borkmann 		int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();
27817a6e288dSDaniel Borkmann 
27827a6e288dSDaniel Borkmann 		skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node);
27837a6e288dSDaniel Borkmann 		if (likely(skb)) {
27847a6e288dSDaniel Borkmann 			skb_reserve(skb, NET_SKB_PAD);
27857a6e288dSDaniel Borkmann 			skb->dev = dev;
27867a6e288dSDaniel Borkmann 		}
27877a6e288dSDaniel Borkmann 	} else {
27887a6e288dSDaniel Borkmann 		 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
27897a6e288dSDaniel Borkmann 	}
2790*3de03596SJohn Fastabend 
2791*3de03596SJohn Fastabend 	if (likely(skb))
2792879c7220SBogdan Hamciuc 		skb_reserve(skb, LL_RESERVED_SPACE(dev));
27937a6e288dSDaniel Borkmann 
27947a6e288dSDaniel Borkmann 	return skb;
27957a6e288dSDaniel Borkmann }
27967a6e288dSDaniel Borkmann 
27971da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
27981da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
27991da177e4SLinus Torvalds {
28001da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
28011da177e4SLinus Torvalds 	__u8 *eth;
28021da177e4SLinus Torvalds 	struct udphdr *udph;
28031da177e4SLinus Torvalds 	int datalen, iplen;
28041da177e4SLinus Torvalds 	struct iphdr *iph;
2805d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IP);
2806ca6549afSSteven Whitehouse 	__be32 *mpls;
280734954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
280834954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
280934954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
281034954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2811fd2ea0a7SDavid S. Miller 	u16 queue_map;
2812ca6549afSSteven Whitehouse 
2813ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2814d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
28151da177e4SLinus Torvalds 
281634954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2817d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
281834954ddcSFrancesco Fondelli 
281964053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
282064053beeSRobert Olsson 	 * fields.
282164053beeSRobert Olsson 	 */
282264053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
2823eb589063SJunchang Wang 	queue_map = pkt_dev->cur_queue_map;
282464053beeSRobert Olsson 
28257ac5459eSDavid S. Miller 	datalen = (odev->hard_header_len + 16) & ~0xf;
2826e99b99b4SRobert Olsson 
28277a6e288dSDaniel Borkmann 	skb = pktgen_alloc_skb(odev, pkt_dev, datalen);
28281da177e4SLinus Torvalds 	if (!skb) {
28291da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
28301da177e4SLinus Torvalds 		return NULL;
28311da177e4SLinus Torvalds 	}
28321da177e4SLinus Torvalds 
28337a6e288dSDaniel Borkmann 	prefetchw(skb->data);
28347ac5459eSDavid S. Miller 	skb_reserve(skb, datalen);
28351da177e4SLinus Torvalds 
28361da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
28371da177e4SLinus Torvalds 	eth = (__u8 *) skb_push(skb, 14);
2838ca6549afSSteven Whitehouse 	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
2839ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2840ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
284134954ddcSFrancesco Fondelli 
284234954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
284334954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
284434954ddcSFrancesco Fondelli 			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
28450f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
28460f37c605SAl Viro 					       pkt_dev->svlan_cfi,
28470f37c605SAl Viro 					       pkt_dev->svlan_p);
284834954ddcSFrancesco Fondelli 			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2849d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
285034954ddcSFrancesco Fondelli 		}
285134954ddcSFrancesco Fondelli 		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
28520f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
28530f37c605SAl Viro 				      pkt_dev->vlan_cfi,
28540f37c605SAl Viro 				      pkt_dev->vlan_p);
285534954ddcSFrancesco Fondelli 		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2856d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IP);
285734954ddcSFrancesco Fondelli 	}
285834954ddcSFrancesco Fondelli 
2859525cebedSThomas Graf 	skb_set_mac_header(skb, 0);
2860525cebedSThomas Graf 	skb_set_network_header(skb, skb->len);
2861525cebedSThomas Graf 	iph = (struct iphdr *) skb_put(skb, sizeof(struct iphdr));
2862525cebedSThomas Graf 
2863525cebedSThomas Graf 	skb_set_transport_header(skb, skb->len);
2864525cebedSThomas Graf 	udph = (struct udphdr *) skb_put(skb, sizeof(struct udphdr));
2865fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
28669e50e3acSJohn Fastabend 	skb->priority = pkt_dev->skb_priority;
28679e50e3acSJohn Fastabend 
28681da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2869252e3346SAl Viro 	*(__be16 *) & eth[12] = protocol;
28701da177e4SLinus Torvalds 
2871ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2872ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
287316dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
28746af773e7SNishank Trivedi 	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr))
28751da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
28761da177e4SLinus Torvalds 
28771da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
28781da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
28791da177e4SLinus Torvalds 	udph->len = htons(datalen + 8);	/* DATA + udphdr */
2880c26bf4a5SThomas Graf 	udph->check = 0;
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 	iph->ihl = 5;
28831da177e4SLinus Torvalds 	iph->version = 4;
28841da177e4SLinus Torvalds 	iph->ttl = 32;
28851ca7768cSFrancesco Fondelli 	iph->tos = pkt_dev->tos;
28861da177e4SLinus Torvalds 	iph->protocol = IPPROTO_UDP;	/* UDP */
28871da177e4SLinus Torvalds 	iph->saddr = pkt_dev->cur_saddr;
28881da177e4SLinus Torvalds 	iph->daddr = pkt_dev->cur_daddr;
288966ed1e5eSEric Dumazet 	iph->id = htons(pkt_dev->ip_id);
289066ed1e5eSEric Dumazet 	pkt_dev->ip_id++;
28911da177e4SLinus Torvalds 	iph->frag_off = 0;
28921da177e4SLinus Torvalds 	iplen = 20 + 8 + datalen;
28931da177e4SLinus Torvalds 	iph->tot_len = htons(iplen);
289403c633e7SThomas Graf 	ip_send_check(iph);
2895ca6549afSSteven Whitehouse 	skb->protocol = protocol;
28961da177e4SLinus Torvalds 	skb->dev = odev;
28971da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
2898c26bf4a5SThomas Graf 
28997744b5f3SSabrina Dubroca 	pktgen_finalize_skb(pkt_dev, skb, datalen);
29007744b5f3SSabrina Dubroca 
2901c26bf4a5SThomas Graf 	if (!(pkt_dev->flags & F_UDPCSUM)) {
2902c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_NONE;
2903c26bf4a5SThomas Graf 	} else if (odev->features & NETIF_F_V4_CSUM) {
2904c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_PARTIAL;
2905c26bf4a5SThomas Graf 		skb->csum = 0;
29067744b5f3SSabrina Dubroca 		udp4_hwcsum(skb, iph->saddr, iph->daddr);
2907c26bf4a5SThomas Graf 	} else {
29087744b5f3SSabrina Dubroca 		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0);
2909c26bf4a5SThomas Graf 
2910c26bf4a5SThomas Graf 		/* add protocol-dependent pseudo-header */
29117744b5f3SSabrina Dubroca 		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
2912c26bf4a5SThomas Graf 						datalen + 8, IPPROTO_UDP, csum);
2913c26bf4a5SThomas Graf 
2914c26bf4a5SThomas Graf 		if (udph->check == 0)
2915c26bf4a5SThomas Graf 			udph->check = CSUM_MANGLED_0;
2916c26bf4a5SThomas Graf 	}
2917c26bf4a5SThomas Graf 
2918a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2919a553e4a6SJamal Hadi Salim 	if (!process_ipsec(pkt_dev, skb, protocol))
2920a553e4a6SJamal Hadi Salim 		return NULL;
2921a553e4a6SJamal Hadi Salim #endif
2922a553e4a6SJamal Hadi Salim 
29231da177e4SLinus Torvalds 	return skb;
29241da177e4SLinus Torvalds }
29251da177e4SLinus Torvalds 
29261da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
29271da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
29281da177e4SLinus Torvalds {
29291da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
29301da177e4SLinus Torvalds 	__u8 *eth;
29311da177e4SLinus Torvalds 	struct udphdr *udph;
2932c26bf4a5SThomas Graf 	int datalen, udplen;
29331da177e4SLinus Torvalds 	struct ipv6hdr *iph;
2934d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IPV6);
2935ca6549afSSteven Whitehouse 	__be32 *mpls;
293634954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
293734954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
293834954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
293934954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2940fd2ea0a7SDavid S. Miller 	u16 queue_map;
2941ca6549afSSteven Whitehouse 
2942ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2943d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
29441da177e4SLinus Torvalds 
294534954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2946d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
294734954ddcSFrancesco Fondelli 
294864053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
294964053beeSRobert Olsson 	 * fields.
295064053beeSRobert Olsson 	 */
295164053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
2952eb589063SJunchang Wang 	queue_map = pkt_dev->cur_queue_map;
295364053beeSRobert Olsson 
29547a6e288dSDaniel Borkmann 	skb = pktgen_alloc_skb(odev, pkt_dev, 16);
29551da177e4SLinus Torvalds 	if (!skb) {
29561da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
29571da177e4SLinus Torvalds 		return NULL;
29581da177e4SLinus Torvalds 	}
29591da177e4SLinus Torvalds 
29607a6e288dSDaniel Borkmann 	prefetchw(skb->data);
29611da177e4SLinus Torvalds 	skb_reserve(skb, 16);
29621da177e4SLinus Torvalds 
29631da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
29641da177e4SLinus Torvalds 	eth = (__u8 *) skb_push(skb, 14);
2965ca6549afSSteven Whitehouse 	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
2966ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2967ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
296834954ddcSFrancesco Fondelli 
296934954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
297034954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
297134954ddcSFrancesco Fondelli 			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
29720f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
29730f37c605SAl Viro 					       pkt_dev->svlan_cfi,
29740f37c605SAl Viro 					       pkt_dev->svlan_p);
297534954ddcSFrancesco Fondelli 			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2976d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
297734954ddcSFrancesco Fondelli 		}
297834954ddcSFrancesco Fondelli 		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
29790f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
29800f37c605SAl Viro 				      pkt_dev->vlan_cfi,
29810f37c605SAl Viro 				      pkt_dev->vlan_p);
298234954ddcSFrancesco Fondelli 		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2983d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
298434954ddcSFrancesco Fondelli 	}
298534954ddcSFrancesco Fondelli 
2986525cebedSThomas Graf 	skb_set_mac_header(skb, 0);
2987525cebedSThomas Graf 	skb_set_network_header(skb, skb->len);
2988525cebedSThomas Graf 	iph = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
2989525cebedSThomas Graf 
2990525cebedSThomas Graf 	skb_set_transport_header(skb, skb->len);
2991525cebedSThomas Graf 	udph = (struct udphdr *) skb_put(skb, sizeof(struct udphdr));
2992fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
29939e50e3acSJohn Fastabend 	skb->priority = pkt_dev->skb_priority;
29941da177e4SLinus Torvalds 
29951da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2996252e3346SAl Viro 	*(__be16 *) &eth[12] = protocol;
29971da177e4SLinus Torvalds 
2998ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2999ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 -
3000ca6549afSSteven Whitehouse 		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
300116dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
30021da177e4SLinus Torvalds 
30035aa8b572SAmerigo Wang 	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) {
30041da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
3005e87cc472SJoe Perches 		net_info_ratelimited("increased datalen to %d\n", datalen);
30061da177e4SLinus Torvalds 	}
30071da177e4SLinus Torvalds 
3008c26bf4a5SThomas Graf 	udplen = datalen + sizeof(struct udphdr);
30091da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
30101da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
3011c26bf4a5SThomas Graf 	udph->len = htons(udplen);
3012c26bf4a5SThomas Graf 	udph->check = 0;
30131da177e4SLinus Torvalds 
3014d5f1ce9aSStephen Hemminger 	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
30151da177e4SLinus Torvalds 
30161ca7768cSFrancesco Fondelli 	if (pkt_dev->traffic_class) {
30171ca7768cSFrancesco Fondelli 		/* Version + traffic class + flow (0) */
3018252e3346SAl Viro 		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
30191ca7768cSFrancesco Fondelli 	}
30201ca7768cSFrancesco Fondelli 
30211da177e4SLinus Torvalds 	iph->hop_limit = 32;
30221da177e4SLinus Torvalds 
3023c26bf4a5SThomas Graf 	iph->payload_len = htons(udplen);
30241da177e4SLinus Torvalds 	iph->nexthdr = IPPROTO_UDP;
30251da177e4SLinus Torvalds 
30264e3fd7a0SAlexey Dobriyan 	iph->daddr = pkt_dev->cur_in6_daddr;
30274e3fd7a0SAlexey Dobriyan 	iph->saddr = pkt_dev->cur_in6_saddr;
30281da177e4SLinus Torvalds 
3029ca6549afSSteven Whitehouse 	skb->protocol = protocol;
30301da177e4SLinus Torvalds 	skb->dev = odev;
30311da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
30321da177e4SLinus Torvalds 
30337744b5f3SSabrina Dubroca 	pktgen_finalize_skb(pkt_dev, skb, datalen);
30347744b5f3SSabrina Dubroca 
3035c26bf4a5SThomas Graf 	if (!(pkt_dev->flags & F_UDPCSUM)) {
3036c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_NONE;
3037c26bf4a5SThomas Graf 	} else if (odev->features & NETIF_F_V6_CSUM) {
3038c26bf4a5SThomas Graf 		skb->ip_summed = CHECKSUM_PARTIAL;
3039c26bf4a5SThomas Graf 		skb->csum_start = skb_transport_header(skb) - skb->head;
3040c26bf4a5SThomas Graf 		skb->csum_offset = offsetof(struct udphdr, check);
3041c26bf4a5SThomas Graf 		udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
3042c26bf4a5SThomas Graf 	} else {
30437744b5f3SSabrina Dubroca 		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0);
3044c26bf4a5SThomas Graf 
3045c26bf4a5SThomas Graf 		/* add protocol-dependent pseudo-header */
3046c26bf4a5SThomas Graf 		udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);
3047c26bf4a5SThomas Graf 
3048c26bf4a5SThomas Graf 		if (udph->check == 0)
3049c26bf4a5SThomas Graf 			udph->check = CSUM_MANGLED_0;
3050c26bf4a5SThomas Graf 	}
3051c26bf4a5SThomas Graf 
30521da177e4SLinus Torvalds 	return skb;
30531da177e4SLinus Torvalds }
30541da177e4SLinus Torvalds 
3055475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev,
30561da177e4SLinus Torvalds 				   struct pktgen_dev *pkt_dev)
30571da177e4SLinus Torvalds {
30581da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
30591da177e4SLinus Torvalds 		return fill_packet_ipv6(odev, pkt_dev);
30601da177e4SLinus Torvalds 	else
30611da177e4SLinus Torvalds 		return fill_packet_ipv4(odev, pkt_dev);
30621da177e4SLinus Torvalds }
30631da177e4SLinus Torvalds 
30641da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
30651da177e4SLinus Torvalds {
30661da177e4SLinus Torvalds 	pkt_dev->seq_num = 1;
30671da177e4SLinus Torvalds 	pkt_dev->idle_acc = 0;
30681da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
30691da177e4SLinus Torvalds 	pkt_dev->tx_bytes = 0;
30701da177e4SLinus Torvalds 	pkt_dev->errors = 0;
30711da177e4SLinus Torvalds }
30721da177e4SLinus Torvalds 
30731da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */
30741da177e4SLinus Torvalds 
30751da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t)
30761da177e4SLinus Torvalds {
3077c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
30781da177e4SLinus Torvalds 	int started = 0;
30791da177e4SLinus Torvalds 
3080f9467eaeSJoe Perches 	func_enter();
30811da177e4SLinus Torvalds 
30828788370aSJesper Dangaard Brouer 	rcu_read_lock();
30838788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
30841da177e4SLinus Torvalds 
30851da177e4SLinus Torvalds 		/*
30861da177e4SLinus Torvalds 		 * setup odev and create initial packet.
30871da177e4SLinus Torvalds 		 */
30881da177e4SLinus Torvalds 		pktgen_setup_inject(pkt_dev);
30891da177e4SLinus Torvalds 
30901da177e4SLinus Torvalds 		if (pkt_dev->odev) {
30911da177e4SLinus Torvalds 			pktgen_clear_counters(pkt_dev);
30921da177e4SLinus Torvalds 			pkt_dev->skb = NULL;
3093398f382cSDaniel Borkmann 			pkt_dev->started_at = pkt_dev->next_tx = ktime_get();
3094fd29cf72SStephen Hemminger 
309516dab72fSJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
30961da177e4SLinus Torvalds 
30971da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Starting");
30988788370aSJesper Dangaard Brouer 			pkt_dev->running = 1;	/* Cranke yeself! */
30991da177e4SLinus Torvalds 			started++;
3100222f1806SLuiz Capitulino 		} else
31011da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Error starting");
31021da177e4SLinus Torvalds 	}
31038788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3104222f1806SLuiz Capitulino 	if (started)
3105222f1806SLuiz Capitulino 		t->control &= ~(T_STOP);
31061da177e4SLinus Torvalds }
31071da177e4SLinus Torvalds 
31084e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn)
31091da177e4SLinus Torvalds {
3110cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31111da177e4SLinus Torvalds 
3112f9467eaeSJoe Perches 	func_enter();
31131da177e4SLinus Torvalds 
31146146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3115cdcdbe0bSLuiz Capitulino 
31164e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
311795ed63f7SArthur Kepner 		t->control |= T_STOP;
3118cdcdbe0bSLuiz Capitulino 
31196146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
31201da177e4SLinus Torvalds }
31211da177e4SLinus Torvalds 
3122648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t)
31231da177e4SLinus Torvalds {
3124648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
31251da177e4SLinus Torvalds 
31268788370aSJesper Dangaard Brouer 	rcu_read_lock();
31278788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
31288788370aSJesper Dangaard Brouer 		if (pkt_dev->running) {
31298788370aSJesper Dangaard Brouer 			rcu_read_unlock();
3130648fda74SStephen Hemminger 			return 1;
31318788370aSJesper Dangaard Brouer 		}
31328788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3133648fda74SStephen Hemminger 	return 0;
31341da177e4SLinus Torvalds }
31351da177e4SLinus Torvalds 
31361da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t)
31371da177e4SLinus Torvalds {
31381da177e4SLinus Torvalds 	while (thread_is_running(t)) {
31391da177e4SLinus Torvalds 
31401da177e4SLinus Torvalds 		msleep_interruptible(100);
31411da177e4SLinus Torvalds 
31421da177e4SLinus Torvalds 		if (signal_pending(current))
31431da177e4SLinus Torvalds 			goto signal;
31441da177e4SLinus Torvalds 	}
31451da177e4SLinus Torvalds 	return 1;
31461da177e4SLinus Torvalds signal:
31471da177e4SLinus Torvalds 	return 0;
31481da177e4SLinus Torvalds }
31491da177e4SLinus Torvalds 
31504e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
31511da177e4SLinus Torvalds {
3152cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31531da177e4SLinus Torvalds 	int sig = 1;
31541da177e4SLinus Torvalds 
31556146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3156cdcdbe0bSLuiz Capitulino 
31574e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
31581da177e4SLinus Torvalds 		sig = pktgen_wait_thread_run(t);
3159222f1806SLuiz Capitulino 		if (sig == 0)
3160222f1806SLuiz Capitulino 			break;
31611da177e4SLinus Torvalds 	}
3162cdcdbe0bSLuiz Capitulino 
3163cdcdbe0bSLuiz Capitulino 	if (sig == 0)
31644e58a027SCong Wang 		list_for_each_entry(t, &pn->pktgen_threads, th_list)
31651da177e4SLinus Torvalds 			t->control |= (T_STOP);
3166cdcdbe0bSLuiz Capitulino 
31676146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
31681da177e4SLinus Torvalds 	return sig;
31691da177e4SLinus Torvalds }
31701da177e4SLinus Torvalds 
31714e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn)
31721da177e4SLinus Torvalds {
3173cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31741da177e4SLinus Torvalds 
3175f9467eaeSJoe Perches 	func_enter();
31761da177e4SLinus Torvalds 
31776146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
31781da177e4SLinus Torvalds 
31794e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
31801da177e4SLinus Torvalds 		t->control |= (T_RUN);
3181cdcdbe0bSLuiz Capitulino 
31826146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
31831da177e4SLinus Torvalds 
318463adc6fbSStephen Hemminger 	/* Propagate thread->control  */
318563adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
31861da177e4SLinus Torvalds 
31874e58a027SCong Wang 	pktgen_wait_all_threads_run(pn);
31881da177e4SLinus Torvalds }
31891da177e4SLinus Torvalds 
31904e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn)
3191eb37b41cSJesse Brandeburg {
3192eb37b41cSJesse Brandeburg 	struct pktgen_thread *t;
3193eb37b41cSJesse Brandeburg 
3194f9467eaeSJoe Perches 	func_enter();
3195eb37b41cSJesse Brandeburg 
3196eb37b41cSJesse Brandeburg 	mutex_lock(&pktgen_thread_lock);
3197eb37b41cSJesse Brandeburg 
31984e58a027SCong Wang 	list_for_each_entry(t, &pn->pktgen_threads, th_list)
3199eb37b41cSJesse Brandeburg 		t->control |= (T_REMDEVALL);
3200eb37b41cSJesse Brandeburg 
3201eb37b41cSJesse Brandeburg 	mutex_unlock(&pktgen_thread_lock);
3202eb37b41cSJesse Brandeburg 
320363adc6fbSStephen Hemminger 	/* Propagate thread->control  */
320463adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
3205eb37b41cSJesse Brandeburg 
32064e58a027SCong Wang 	pktgen_wait_all_threads_run(pn);
3207eb37b41cSJesse Brandeburg }
3208eb37b41cSJesse Brandeburg 
32091da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
32101da177e4SLinus Torvalds {
3211fd29cf72SStephen Hemminger 	__u64 bps, mbps, pps;
32121da177e4SLinus Torvalds 	char *p = pkt_dev->result;
3213fd29cf72SStephen Hemminger 	ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
3214fd29cf72SStephen Hemminger 				    pkt_dev->started_at);
3215fd29cf72SStephen Hemminger 	ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
32161da177e4SLinus Torvalds 
321703a14ab1SDaniel Turull 	p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
3218fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(elapsed),
3219fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
3220fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(idle),
32211da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->sofar,
32221da177e4SLinus Torvalds 		     pkt_dev->cur_pkt_size, nr_frags);
32231da177e4SLinus Torvalds 
3224fd29cf72SStephen Hemminger 	pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
3225fd29cf72SStephen Hemminger 			ktime_to_ns(elapsed));
32261da177e4SLinus Torvalds 
32271da177e4SLinus Torvalds 	bps = pps * 8 * pkt_dev->cur_pkt_size;
32281da177e4SLinus Torvalds 
32291da177e4SLinus Torvalds 	mbps = bps;
32301da177e4SLinus Torvalds 	do_div(mbps, 1000000);
32311da177e4SLinus Torvalds 	p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
32321da177e4SLinus Torvalds 		     (unsigned long long)pps,
32331da177e4SLinus Torvalds 		     (unsigned long long)mbps,
32341da177e4SLinus Torvalds 		     (unsigned long long)bps,
32351da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->errors);
32361da177e4SLinus Torvalds }
32371da177e4SLinus Torvalds 
32381da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */
32391da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
32401da177e4SLinus Torvalds {
3241222f1806SLuiz Capitulino 	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
32421da177e4SLinus Torvalds 
32431da177e4SLinus Torvalds 	if (!pkt_dev->running) {
3244294a0b7fSJoe Perches 		pr_warn("interface: %s is already stopped\n",
3245f9467eaeSJoe Perches 			pkt_dev->odevname);
32461da177e4SLinus Torvalds 		return -EINVAL;
32471da177e4SLinus Torvalds 	}
32481da177e4SLinus Torvalds 
32498788370aSJesper Dangaard Brouer 	pkt_dev->running = 0;
32503bda06a3SStephen Hemminger 	kfree_skb(pkt_dev->skb);
32513bda06a3SStephen Hemminger 	pkt_dev->skb = NULL;
3252398f382cSDaniel Borkmann 	pkt_dev->stopped_at = ktime_get();
32531da177e4SLinus Torvalds 
325495ed63f7SArthur Kepner 	show_results(pkt_dev, nr_frags);
32551da177e4SLinus Torvalds 
32561da177e4SLinus Torvalds 	return 0;
32571da177e4SLinus Torvalds }
32581da177e4SLinus Torvalds 
32591da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
32601da177e4SLinus Torvalds {
3261c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev, *best = NULL;
32621da177e4SLinus Torvalds 
32638788370aSJesper Dangaard Brouer 	rcu_read_lock();
32648788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3265c26a8016SLuiz Capitulino 		if (!pkt_dev->running)
3266222f1806SLuiz Capitulino 			continue;
3267222f1806SLuiz Capitulino 		if (best == NULL)
3268c26a8016SLuiz Capitulino 			best = pkt_dev;
3269398f382cSDaniel Borkmann 		else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0)
3270c26a8016SLuiz Capitulino 			best = pkt_dev;
32711da177e4SLinus Torvalds 	}
32728788370aSJesper Dangaard Brouer 	rcu_read_unlock();
32738788370aSJesper Dangaard Brouer 
32741da177e4SLinus Torvalds 	return best;
32751da177e4SLinus Torvalds }
32761da177e4SLinus Torvalds 
3277222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t)
3278222f1806SLuiz Capitulino {
3279c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
32801da177e4SLinus Torvalds 
3281f9467eaeSJoe Perches 	func_enter();
32821da177e4SLinus Torvalds 
32838788370aSJesper Dangaard Brouer 	rcu_read_lock();
32841da177e4SLinus Torvalds 
32858788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3286c26a8016SLuiz Capitulino 		pktgen_stop_device(pkt_dev);
328795ed63f7SArthur Kepner 	}
328895ed63f7SArthur Kepner 
32898788370aSJesper Dangaard Brouer 	rcu_read_unlock();
329095ed63f7SArthur Kepner }
329195ed63f7SArthur Kepner 
329295ed63f7SArthur Kepner /*
329395ed63f7SArthur Kepner  * one of our devices needs to be removed - find it
329495ed63f7SArthur Kepner  * and remove it
329595ed63f7SArthur Kepner  */
329695ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t)
329795ed63f7SArthur Kepner {
3298c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3299c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
330095ed63f7SArthur Kepner 
3301f9467eaeSJoe Perches 	func_enter();
330295ed63f7SArthur Kepner 
3303c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3304c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
330595ed63f7SArthur Kepner 
3306222f1806SLuiz Capitulino 		if (!cur->removal_mark)
3307222f1806SLuiz Capitulino 			continue;
330895ed63f7SArthur Kepner 
330995ed63f7SArthur Kepner 		kfree_skb(cur->skb);
331095ed63f7SArthur Kepner 		cur->skb = NULL;
331195ed63f7SArthur Kepner 
331295ed63f7SArthur Kepner 		pktgen_remove_device(t, cur);
331395ed63f7SArthur Kepner 
331495ed63f7SArthur Kepner 		break;
331595ed63f7SArthur Kepner 	}
33161da177e4SLinus Torvalds }
33171da177e4SLinus Torvalds 
33181da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t)
33191da177e4SLinus Torvalds {
3320c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3321c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
33221da177e4SLinus Torvalds 
3323f9467eaeSJoe Perches 	func_enter();
3324f9467eaeSJoe Perches 
33251da177e4SLinus Torvalds 	/* Remove all devices, free mem */
33261da177e4SLinus Torvalds 
3327c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3328c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
332995ed63f7SArthur Kepner 
333095ed63f7SArthur Kepner 		kfree_skb(cur->skb);
333195ed63f7SArthur Kepner 		cur->skb = NULL;
333295ed63f7SArthur Kepner 
33331da177e4SLinus Torvalds 		pktgen_remove_device(t, cur);
33341da177e4SLinus Torvalds 	}
33351da177e4SLinus Torvalds }
33361da177e4SLinus Torvalds 
33371da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t)
33381da177e4SLinus Torvalds {
33391da177e4SLinus Torvalds 	/* Remove from the thread list */
33404e58a027SCong Wang 	remove_proc_entry(t->tsk->comm, t->net->proc_dir);
33411da177e4SLinus Torvalds }
33421da177e4SLinus Torvalds 
3343ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev)
33443791decbSStephen Hemminger {
3345398f382cSDaniel Borkmann 	ktime_t idle_start = ktime_get();
33463791decbSStephen Hemminger 	schedule();
3347398f382cSDaniel Borkmann 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
33483791decbSStephen Hemminger }
33493791decbSStephen Hemminger 
3350ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
3351ef87979cSStephen Hemminger {
3352398f382cSDaniel Borkmann 	ktime_t idle_start = ktime_get();
3353ef87979cSStephen Hemminger 
3354ef87979cSStephen Hemminger 	while (atomic_read(&(pkt_dev->skb->users)) != 1) {
3355ef87979cSStephen Hemminger 		if (signal_pending(current))
3356ef87979cSStephen Hemminger 			break;
3357ef87979cSStephen Hemminger 
3358ef87979cSStephen Hemminger 		if (need_resched())
3359ef87979cSStephen Hemminger 			pktgen_resched(pkt_dev);
3360ef87979cSStephen Hemminger 		else
3361ef87979cSStephen Hemminger 			cpu_relax();
3362ef87979cSStephen Hemminger 	}
3363398f382cSDaniel Borkmann 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
3364ef87979cSStephen Hemminger }
3365fd29cf72SStephen Hemminger 
3366475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev)
33671da177e4SLinus Torvalds {
336838b2cf29SAlexei Starovoitov 	unsigned int burst = ACCESS_ONCE(pkt_dev->burst);
336900829823SStephen Hemminger 	struct net_device *odev = pkt_dev->odev;
3370fd2ea0a7SDavid S. Miller 	struct netdev_queue *txq;
337162f64aedSAlexei Starovoitov 	struct sk_buff *skb;
33721da177e4SLinus Torvalds 	int ret;
33731da177e4SLinus Torvalds 
3374ef87979cSStephen Hemminger 	/* If device is offline, then don't send */
3375ef87979cSStephen Hemminger 	if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) {
33761da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
33773791decbSStephen Hemminger 		return;
33781da177e4SLinus Torvalds 	}
33791da177e4SLinus Torvalds 
3380ef87979cSStephen Hemminger 	/* This is max DELAY, this has special meaning of
3381ef87979cSStephen Hemminger 	 * "never transmit"
3382ef87979cSStephen Hemminger 	 */
3383ef87979cSStephen Hemminger 	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
3384398f382cSDaniel Borkmann 		pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX);
3385ef87979cSStephen Hemminger 		return;
3386ef87979cSStephen Hemminger 	}
3387ef87979cSStephen Hemminger 
3388ef87979cSStephen Hemminger 	/* If no skb or clone count exhausted then get new one */
33897d7bb1cfSStephen Hemminger 	if (!pkt_dev->skb || (pkt_dev->last_ok &&
33907d7bb1cfSStephen Hemminger 			      ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
33911da177e4SLinus Torvalds 		/* build a new pkt */
33921da177e4SLinus Torvalds 		kfree_skb(pkt_dev->skb);
33931da177e4SLinus Torvalds 
33941da177e4SLinus Torvalds 		pkt_dev->skb = fill_packet(odev, pkt_dev);
33951da177e4SLinus Torvalds 		if (pkt_dev->skb == NULL) {
3396f9467eaeSJoe Perches 			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
33971da177e4SLinus Torvalds 			schedule();
33981da177e4SLinus Torvalds 			pkt_dev->clone_count--;	/* back out increment, OOM */
33993791decbSStephen Hemminger 			return;
34001da177e4SLinus Torvalds 		}
3401baac8564SEric Dumazet 		pkt_dev->last_pkt_size = pkt_dev->skb->len;
34021da177e4SLinus Torvalds 		pkt_dev->clone_count = 0;	/* reset counter */
34031da177e4SLinus Torvalds 	}
34041da177e4SLinus Torvalds 
3405ef87979cSStephen Hemminger 	if (pkt_dev->delay && pkt_dev->last_ok)
3406ef87979cSStephen Hemminger 		spin(pkt_dev, pkt_dev->next_tx);
3407ef87979cSStephen Hemminger 
340862f64aedSAlexei Starovoitov 	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) {
340962f64aedSAlexei Starovoitov 		skb = pkt_dev->skb;
341062f64aedSAlexei Starovoitov 		skb->protocol = eth_type_trans(skb, skb->dev);
341162f64aedSAlexei Starovoitov 		atomic_add(burst, &skb->users);
341262f64aedSAlexei Starovoitov 		local_bh_disable();
341362f64aedSAlexei Starovoitov 		do {
341462f64aedSAlexei Starovoitov 			ret = netif_receive_skb(skb);
341562f64aedSAlexei Starovoitov 			if (ret == NET_RX_DROP)
341662f64aedSAlexei Starovoitov 				pkt_dev->errors++;
341762f64aedSAlexei Starovoitov 			pkt_dev->sofar++;
341862f64aedSAlexei Starovoitov 			pkt_dev->seq_num++;
341962f64aedSAlexei Starovoitov 			if (atomic_read(&skb->users) != burst) {
342062f64aedSAlexei Starovoitov 				/* skb was queued by rps/rfs or taps,
342162f64aedSAlexei Starovoitov 				 * so cannot reuse this skb
342262f64aedSAlexei Starovoitov 				 */
342362f64aedSAlexei Starovoitov 				atomic_sub(burst - 1, &skb->users);
342462f64aedSAlexei Starovoitov 				/* get out of the loop and wait
342562f64aedSAlexei Starovoitov 				 * until skb is consumed
342662f64aedSAlexei Starovoitov 				 */
342762f64aedSAlexei Starovoitov 				break;
342862f64aedSAlexei Starovoitov 			}
342962f64aedSAlexei Starovoitov 			/* skb was 'freed' by stack, so clean few
343062f64aedSAlexei Starovoitov 			 * bits and reuse it
343162f64aedSAlexei Starovoitov 			 */
343262f64aedSAlexei Starovoitov #ifdef CONFIG_NET_CLS_ACT
343362f64aedSAlexei Starovoitov 			skb->tc_verd = 0; /* reset reclass/redir ttl */
343462f64aedSAlexei Starovoitov #endif
343562f64aedSAlexei Starovoitov 		} while (--burst > 0);
343662f64aedSAlexei Starovoitov 		goto out; /* Skips xmit_mode M_START_XMIT */
343762f64aedSAlexei Starovoitov 	}
343862f64aedSAlexei Starovoitov 
343910c51b56SDaniel Borkmann 	txq = skb_get_tx_queue(odev, pkt_dev->skb);
3440fd2ea0a7SDavid S. Miller 
34410f2eea4bSDaniel Borkmann 	local_bh_disable();
34420f2eea4bSDaniel Borkmann 
34430f2eea4bSDaniel Borkmann 	HARD_TX_LOCK(odev, txq, smp_processor_id());
34445b8db2f5SStephen Hemminger 
34456f25cd47SDaniel Borkmann 	if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) {
3446ef87979cSStephen Hemminger 		ret = NETDEV_TX_BUSY;
34470835acfeSEric Dumazet 		pkt_dev->last_ok = 0;
34480835acfeSEric Dumazet 		goto unlock;
34490835acfeSEric Dumazet 	}
345038b2cf29SAlexei Starovoitov 	atomic_add(burst, &pkt_dev->skb->users);
345138b2cf29SAlexei Starovoitov 
345238b2cf29SAlexei Starovoitov xmit_more:
345338b2cf29SAlexei Starovoitov 	ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0);
3454ef87979cSStephen Hemminger 
34555b8db2f5SStephen Hemminger 	switch (ret) {
34565b8db2f5SStephen Hemminger 	case NETDEV_TX_OK:
34571da177e4SLinus Torvalds 		pkt_dev->last_ok = 1;
34581da177e4SLinus Torvalds 		pkt_dev->sofar++;
34591da177e4SLinus Torvalds 		pkt_dev->seq_num++;
3460baac8564SEric Dumazet 		pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
346138b2cf29SAlexei Starovoitov 		if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq))
346238b2cf29SAlexei Starovoitov 			goto xmit_more;
34635b8db2f5SStephen Hemminger 		break;
3464f466dba1SJohn Fastabend 	case NET_XMIT_DROP:
3465f466dba1SJohn Fastabend 	case NET_XMIT_CN:
3466f466dba1SJohn Fastabend 	case NET_XMIT_POLICED:
3467f466dba1SJohn Fastabend 		/* skb has been consumed */
3468f466dba1SJohn Fastabend 		pkt_dev->errors++;
3469f466dba1SJohn Fastabend 		break;
34705b8db2f5SStephen Hemminger 	default: /* Drivers are not supposed to return other values! */
3471e87cc472SJoe Perches 		net_info_ratelimited("%s xmit error: %d\n",
3472e87cc472SJoe Perches 				     pkt_dev->odevname, ret);
34731da177e4SLinus Torvalds 		pkt_dev->errors++;
34745b8db2f5SStephen Hemminger 		/* fallthru */
3475ef87979cSStephen Hemminger 	case NETDEV_TX_LOCKED:
34765b8db2f5SStephen Hemminger 	case NETDEV_TX_BUSY:
34775b8db2f5SStephen Hemminger 		/* Retry it next time */
34785b8db2f5SStephen Hemminger 		atomic_dec(&(pkt_dev->skb->users));
34791da177e4SLinus Torvalds 		pkt_dev->last_ok = 0;
34801da177e4SLinus Torvalds 	}
348138b2cf29SAlexei Starovoitov 	if (unlikely(burst))
348238b2cf29SAlexei Starovoitov 		atomic_sub(burst, &pkt_dev->skb->users);
34830835acfeSEric Dumazet unlock:
34840f2eea4bSDaniel Borkmann 	HARD_TX_UNLOCK(odev, txq);
34850f2eea4bSDaniel Borkmann 
348662f64aedSAlexei Starovoitov out:
34870f2eea4bSDaniel Borkmann 	local_bh_enable();
34881da177e4SLinus Torvalds 
34891da177e4SLinus Torvalds 	/* If pkt_dev->count is zero, then run forever */
34901da177e4SLinus Torvalds 	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
3491ef87979cSStephen Hemminger 		pktgen_wait_for_skb(pkt_dev);
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds 		/* Done with this */
34941da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
34951da177e4SLinus Torvalds 	}
34961da177e4SLinus Torvalds }
34971da177e4SLinus Torvalds 
34981da177e4SLinus Torvalds /*
34991da177e4SLinus Torvalds  * Main loop of the thread goes here
35001da177e4SLinus Torvalds  */
35011da177e4SLinus Torvalds 
3502ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg)
35031da177e4SLinus Torvalds {
35041da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
3505ee74baa7SDavid S. Miller 	struct pktgen_thread *t = arg;
35061da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
35071da177e4SLinus Torvalds 	int cpu = t->cpu;
35081da177e4SLinus Torvalds 
3509ee74baa7SDavid S. Miller 	BUG_ON(smp_processor_id() != cpu);
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds 	init_waitqueue_head(&t->queue);
3512d3ede327SDenis V. Lunev 	complete(&t->start_done);
35131da177e4SLinus Torvalds 
3514f9467eaeSJoe Perches 	pr_debug("starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
35151da177e4SLinus Torvalds 
351683144186SRafael J. Wysocki 	set_freezable();
351783144186SRafael J. Wysocki 
3518ee74baa7SDavid S. Miller 	while (!kthread_should_stop()) {
3519ee74baa7SDavid S. Miller 		pkt_dev = next_to_run(t);
3520ee74baa7SDavid S. Miller 
3521ef87979cSStephen Hemminger 		if (unlikely(!pkt_dev && t->control == 0)) {
35224e58a027SCong Wang 			if (t->net->pktgen_exiting)
3523551eaff1SEric Dumazet 				break;
3524ef87979cSStephen Hemminger 			wait_event_interruptible_timeout(t->queue,
3525ef87979cSStephen Hemminger 							 t->control != 0,
3526ef87979cSStephen Hemminger 							 HZ/10);
35271b3f720bSRafael J. Wysocki 			try_to_freeze();
3528ef87979cSStephen Hemminger 			continue;
3529ee74baa7SDavid S. Miller 		}
35301da177e4SLinus Torvalds 
3531ef87979cSStephen Hemminger 		if (likely(pkt_dev)) {
35321da177e4SLinus Torvalds 			pktgen_xmit(pkt_dev);
35331da177e4SLinus Torvalds 
3534ef87979cSStephen Hemminger 			if (need_resched())
3535ef87979cSStephen Hemminger 				pktgen_resched(pkt_dev);
3536ef87979cSStephen Hemminger 			else
3537ef87979cSStephen Hemminger 				cpu_relax();
3538ef87979cSStephen Hemminger 		}
3539ef87979cSStephen Hemminger 
35401da177e4SLinus Torvalds 		if (t->control & T_STOP) {
35411da177e4SLinus Torvalds 			pktgen_stop(t);
35421da177e4SLinus Torvalds 			t->control &= ~(T_STOP);
35431da177e4SLinus Torvalds 		}
35441da177e4SLinus Torvalds 
35451da177e4SLinus Torvalds 		if (t->control & T_RUN) {
35461da177e4SLinus Torvalds 			pktgen_run(t);
35471da177e4SLinus Torvalds 			t->control &= ~(T_RUN);
35481da177e4SLinus Torvalds 		}
35491da177e4SLinus Torvalds 
355095ed63f7SArthur Kepner 		if (t->control & T_REMDEVALL) {
35511da177e4SLinus Torvalds 			pktgen_rem_all_ifs(t);
355295ed63f7SArthur Kepner 			t->control &= ~(T_REMDEVALL);
355395ed63f7SArthur Kepner 		}
355495ed63f7SArthur Kepner 
355595ed63f7SArthur Kepner 		if (t->control & T_REMDEV) {
355695ed63f7SArthur Kepner 			pktgen_rem_one_if(t);
35571da177e4SLinus Torvalds 			t->control &= ~(T_REMDEV);
35581da177e4SLinus Torvalds 		}
35591da177e4SLinus Torvalds 
356009fe3ef4SAndrew Morton 		try_to_freeze();
35611da177e4SLinus Torvalds 	}
35621da177e4SLinus Torvalds 
3563f9467eaeSJoe Perches 	pr_debug("%s stopping all device\n", t->tsk->comm);
35641da177e4SLinus Torvalds 	pktgen_stop(t);
35651da177e4SLinus Torvalds 
3566f9467eaeSJoe Perches 	pr_debug("%s removing all device\n", t->tsk->comm);
35671da177e4SLinus Torvalds 	pktgen_rem_all_ifs(t);
35681da177e4SLinus Torvalds 
3569f9467eaeSJoe Perches 	pr_debug("%s removing thread\n", t->tsk->comm);
35701da177e4SLinus Torvalds 	pktgen_rem_thread(t);
3571cdcdbe0bSLuiz Capitulino 
3572ee74baa7SDavid S. Miller 	return 0;
35731da177e4SLinus Torvalds }
35741da177e4SLinus Torvalds 
3575222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
35763e984840SEric Dumazet 					  const char *ifname, bool exact)
35771da177e4SLinus Torvalds {
3578c26a8016SLuiz Capitulino 	struct pktgen_dev *p, *pkt_dev = NULL;
35793e984840SEric Dumazet 	size_t len = strlen(ifname);
35801da177e4SLinus Torvalds 
35818788370aSJesper Dangaard Brouer 	rcu_read_lock();
35828788370aSJesper Dangaard Brouer 	list_for_each_entry_rcu(p, &t->if_list, list)
35833e984840SEric Dumazet 		if (strncmp(p->odevname, ifname, len) == 0) {
35843e984840SEric Dumazet 			if (p->odevname[len]) {
35853e984840SEric Dumazet 				if (exact || p->odevname[len] != '@')
35863e984840SEric Dumazet 					continue;
35873e984840SEric Dumazet 			}
3588c26a8016SLuiz Capitulino 			pkt_dev = p;
35891da177e4SLinus Torvalds 			break;
35901da177e4SLinus Torvalds 		}
35911da177e4SLinus Torvalds 
35928788370aSJesper Dangaard Brouer 	rcu_read_unlock();
3593f9467eaeSJoe Perches 	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
35941da177e4SLinus Torvalds 	return pkt_dev;
35951da177e4SLinus Torvalds }
35961da177e4SLinus Torvalds 
35971da177e4SLinus Torvalds /*
35981da177e4SLinus Torvalds  * Adds a dev at front of if_list.
35991da177e4SLinus Torvalds  */
36001da177e4SLinus Torvalds 
3601222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t,
3602222f1806SLuiz Capitulino 			     struct pktgen_dev *pkt_dev)
36031da177e4SLinus Torvalds {
36041da177e4SLinus Torvalds 	int rv = 0;
36051da177e4SLinus Torvalds 
36068788370aSJesper Dangaard Brouer 	/* This function cannot be called concurrently, as its called
36078788370aSJesper Dangaard Brouer 	 * under pktgen_thread_lock mutex, but it can run from
36088788370aSJesper Dangaard Brouer 	 * userspace on another CPU than the kthread.  The if_lock()
36098788370aSJesper Dangaard Brouer 	 * is used here to sync with concurrent instances of
36108788370aSJesper Dangaard Brouer 	 * _rem_dev_from_if_list() invoked via kthread, which is also
36118788370aSJesper Dangaard Brouer 	 * updating the if_list */
36121da177e4SLinus Torvalds 	if_lock(t);
36131da177e4SLinus Torvalds 
36141da177e4SLinus Torvalds 	if (pkt_dev->pg_thread) {
3615f9467eaeSJoe Perches 		pr_err("ERROR: already assigned to a thread\n");
36161da177e4SLinus Torvalds 		rv = -EBUSY;
36171da177e4SLinus Torvalds 		goto out;
36181da177e4SLinus Torvalds 	}
3619c26a8016SLuiz Capitulino 
36201da177e4SLinus Torvalds 	pkt_dev->running = 0;
36218788370aSJesper Dangaard Brouer 	pkt_dev->pg_thread = t;
36228788370aSJesper Dangaard Brouer 	list_add_rcu(&pkt_dev->list, &t->if_list);
36231da177e4SLinus Torvalds 
36241da177e4SLinus Torvalds out:
36251da177e4SLinus Torvalds 	if_unlock(t);
36261da177e4SLinus Torvalds 	return rv;
36271da177e4SLinus Torvalds }
36281da177e4SLinus Torvalds 
36291da177e4SLinus Torvalds /* Called under thread lock */
36301da177e4SLinus Torvalds 
36311da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
36321da177e4SLinus Torvalds {
36331da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev;
363439df232fSStephen Hemminger 	int err;
36353291b9dbSEric Dumazet 	int node = cpu_to_node(t->cpu);
36361da177e4SLinus Torvalds 
36371da177e4SLinus Torvalds 	/* We don't allow a device to be on several threads */
36381da177e4SLinus Torvalds 
36394e58a027SCong Wang 	pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND);
3640d50a6b56SStephen Hemminger 	if (pkt_dev) {
3641f9467eaeSJoe Perches 		pr_err("ERROR: interface already used\n");
3642d50a6b56SStephen Hemminger 		return -EBUSY;
3643d50a6b56SStephen Hemminger 	}
36441da177e4SLinus Torvalds 
36453291b9dbSEric Dumazet 	pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node);
36461da177e4SLinus Torvalds 	if (!pkt_dev)
36471da177e4SLinus Torvalds 		return -ENOMEM;
36481da177e4SLinus Torvalds 
3649593f63b0SEric Dumazet 	strcpy(pkt_dev->odevname, ifname);
365068d5ac2eSWANG Cong 	pkt_dev->flows = vzalloc_node(MAX_CFLOWS * sizeof(struct flow_state),
36513291b9dbSEric Dumazet 				      node);
36521da177e4SLinus Torvalds 	if (pkt_dev->flows == NULL) {
36531da177e4SLinus Torvalds 		kfree(pkt_dev);
36541da177e4SLinus Torvalds 		return -ENOMEM;
36551da177e4SLinus Torvalds 	}
36561da177e4SLinus Torvalds 
365795ed63f7SArthur Kepner 	pkt_dev->removal_mark = 0;
36581da177e4SLinus Torvalds 	pkt_dev->nfrags = 0;
3659fd29cf72SStephen Hemminger 	pkt_dev->delay = pg_delay_d;
36601da177e4SLinus Torvalds 	pkt_dev->count = pg_count_d;
36611da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
36621da177e4SLinus Torvalds 	pkt_dev->udp_src_min = 9;	/* sink port */
36631da177e4SLinus Torvalds 	pkt_dev->udp_src_max = 9;
36641da177e4SLinus Torvalds 	pkt_dev->udp_dst_min = 9;
36651da177e4SLinus Torvalds 	pkt_dev->udp_dst_max = 9;
366634954ddcSFrancesco Fondelli 	pkt_dev->vlan_p = 0;
366734954ddcSFrancesco Fondelli 	pkt_dev->vlan_cfi = 0;
366834954ddcSFrancesco Fondelli 	pkt_dev->vlan_id = 0xffff;
366934954ddcSFrancesco Fondelli 	pkt_dev->svlan_p = 0;
367034954ddcSFrancesco Fondelli 	pkt_dev->svlan_cfi = 0;
367134954ddcSFrancesco Fondelli 	pkt_dev->svlan_id = 0xffff;
367238b2cf29SAlexei Starovoitov 	pkt_dev->burst = 1;
3673e99b99b4SRobert Olsson 	pkt_dev->node = -1;
367434954ddcSFrancesco Fondelli 
36754e58a027SCong Wang 	err = pktgen_setup_dev(t->net, pkt_dev, ifname);
367639df232fSStephen Hemminger 	if (err)
367739df232fSStephen Hemminger 		goto out1;
3678d8873315SNeil Horman 	if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
3679d8873315SNeil Horman 		pkt_dev->clone_skb = pg_clone_skb_d;
36801da177e4SLinus Torvalds 
36814e58a027SCong Wang 	pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir,
36825efdccbcSDenis V. Lunev 					  &pktgen_if_fops, pkt_dev);
368339df232fSStephen Hemminger 	if (!pkt_dev->entry) {
3684f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3685d50a6b56SStephen Hemminger 		       PG_PROC_DIR, ifname);
368639df232fSStephen Hemminger 		err = -EINVAL;
368739df232fSStephen Hemminger 		goto out2;
368839df232fSStephen Hemminger 	}
3689a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3690a553e4a6SJamal Hadi Salim 	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
3691a553e4a6SJamal Hadi Salim 	pkt_dev->ipsproto = IPPROTO_ESP;
3692cf93d47eSFan Du 
3693cf93d47eSFan Du 	/* xfrm tunnel mode needs additional dst to extract outter
3694cf93d47eSFan Du 	 * ip header protocol/ttl/id field, here creat a phony one.
3695cf93d47eSFan Du 	 * instead of looking for a valid rt, which definitely hurting
3696cf93d47eSFan Du 	 * performance under such circumstance.
3697cf93d47eSFan Du 	 */
3698cf93d47eSFan Du 	pkt_dev->dstops.family = AF_INET;
3699cf93d47eSFan Du 	pkt_dev->dst.dev = pkt_dev->odev;
3700cf93d47eSFan Du 	dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false);
3701cf93d47eSFan Du 	pkt_dev->dst.child = &pkt_dev->dst;
3702cf93d47eSFan Du 	pkt_dev->dst.ops = &pkt_dev->dstops;
3703a553e4a6SJamal Hadi Salim #endif
370439df232fSStephen Hemminger 
370539df232fSStephen Hemminger 	return add_dev_to_thread(t, pkt_dev);
370639df232fSStephen Hemminger out2:
370739df232fSStephen Hemminger 	dev_put(pkt_dev->odev);
370839df232fSStephen Hemminger out1:
3709a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3710a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3711a553e4a6SJamal Hadi Salim #endif
37121da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
37131da177e4SLinus Torvalds 	kfree(pkt_dev);
371439df232fSStephen Hemminger 	return err;
37151da177e4SLinus Torvalds }
37161da177e4SLinus Torvalds 
37174e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
37181da177e4SLinus Torvalds {
3719cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3720d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3721ee74baa7SDavid S. Miller 	struct task_struct *p;
37221da177e4SLinus Torvalds 
37233291b9dbSEric Dumazet 	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
37243291b9dbSEric Dumazet 			 cpu_to_node(cpu));
37251da177e4SLinus Torvalds 	if (!t) {
3726f9467eaeSJoe Perches 		pr_err("ERROR: out of memory, can't create new thread\n");
37271da177e4SLinus Torvalds 		return -ENOMEM;
37281da177e4SLinus Torvalds 	}
37291da177e4SLinus Torvalds 
37301da177e4SLinus Torvalds 	spin_lock_init(&t->if_lock);
37311da177e4SLinus Torvalds 	t->cpu = cpu;
37321da177e4SLinus Torvalds 
3733ee74baa7SDavid S. Miller 	INIT_LIST_HEAD(&t->if_list);
3734ee74baa7SDavid S. Miller 
37354e58a027SCong Wang 	list_add_tail(&t->th_list, &pn->pktgen_threads);
3736d3ede327SDenis V. Lunev 	init_completion(&t->start_done);
3737ee74baa7SDavid S. Miller 
373894dcf29aSEric Dumazet 	p = kthread_create_on_node(pktgen_thread_worker,
373994dcf29aSEric Dumazet 				   t,
374094dcf29aSEric Dumazet 				   cpu_to_node(cpu),
374194dcf29aSEric Dumazet 				   "kpktgend_%d", cpu);
3742ee74baa7SDavid S. Miller 	if (IS_ERR(p)) {
3743f9467eaeSJoe Perches 		pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
3744ee74baa7SDavid S. Miller 		list_del(&t->th_list);
3745ee74baa7SDavid S. Miller 		kfree(t);
3746ee74baa7SDavid S. Miller 		return PTR_ERR(p);
3747ee74baa7SDavid S. Miller 	}
3748ee74baa7SDavid S. Miller 	kthread_bind(p, cpu);
3749ee74baa7SDavid S. Miller 	t->tsk = p;
3750ee74baa7SDavid S. Miller 
37514e58a027SCong Wang 	pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir,
37525efdccbcSDenis V. Lunev 			      &pktgen_thread_fops, t);
3753d50a6b56SStephen Hemminger 	if (!pe) {
3754f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3755ee74baa7SDavid S. Miller 		       PG_PROC_DIR, t->tsk->comm);
3756ee74baa7SDavid S. Miller 		kthread_stop(p);
3757ee74baa7SDavid S. Miller 		list_del(&t->th_list);
37581da177e4SLinus Torvalds 		kfree(t);
37591da177e4SLinus Torvalds 		return -EINVAL;
37601da177e4SLinus Torvalds 	}
3761d50a6b56SStephen Hemminger 
37624e58a027SCong Wang 	t->net = pn;
37631fbe4b46SOleg Nesterov 	get_task_struct(p);
3764ee74baa7SDavid S. Miller 	wake_up_process(p);
3765d3ede327SDenis V. Lunev 	wait_for_completion(&t->start_done);
37661da177e4SLinus Torvalds 
37671da177e4SLinus Torvalds 	return 0;
37681da177e4SLinus Torvalds }
37691da177e4SLinus Torvalds 
37701da177e4SLinus Torvalds /*
37711da177e4SLinus Torvalds  * Removes a device from the thread if_list.
37721da177e4SLinus Torvalds  */
3773222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t,
3774222f1806SLuiz Capitulino 				  struct pktgen_dev *pkt_dev)
37751da177e4SLinus Torvalds {
3776c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3777c26a8016SLuiz Capitulino 	struct pktgen_dev *p;
37781da177e4SLinus Torvalds 
37798788370aSJesper Dangaard Brouer 	if_lock(t);
3780c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3781c26a8016SLuiz Capitulino 		p = list_entry(q, struct pktgen_dev, list);
3782c26a8016SLuiz Capitulino 		if (p == pkt_dev)
37838788370aSJesper Dangaard Brouer 			list_del_rcu(&p->list);
37841da177e4SLinus Torvalds 	}
37858788370aSJesper Dangaard Brouer 	if_unlock(t);
37861da177e4SLinus Torvalds }
37871da177e4SLinus Torvalds 
3788222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t,
3789222f1806SLuiz Capitulino 				struct pktgen_dev *pkt_dev)
37901da177e4SLinus Torvalds {
3791f9467eaeSJoe Perches 	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
37921da177e4SLinus Torvalds 
37931da177e4SLinus Torvalds 	if (pkt_dev->running) {
3794294a0b7fSJoe Perches 		pr_warn("WARNING: trying to remove a running interface, stopping it now\n");
37951da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
37961da177e4SLinus Torvalds 	}
37971da177e4SLinus Torvalds 
37981da177e4SLinus Torvalds 	/* Dis-associate from the interface */
37991da177e4SLinus Torvalds 
38001da177e4SLinus Torvalds 	if (pkt_dev->odev) {
38011da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
38021da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
38031da177e4SLinus Torvalds 	}
38041da177e4SLinus Torvalds 
38058788370aSJesper Dangaard Brouer 	/* Remove proc before if_list entry, because add_device uses
38068788370aSJesper Dangaard Brouer 	 * list to determine if interface already exist, avoid race
38078788370aSJesper Dangaard Brouer 	 * with proc_create_data() */
3808a8ca16eaSDavid Howells 	proc_remove(pkt_dev->entry);
38091da177e4SLinus Torvalds 
38108788370aSJesper Dangaard Brouer 	/* And update the thread if_list */
38118788370aSJesper Dangaard Brouer 	_rem_dev_from_if_list(t, pkt_dev);
38128788370aSJesper Dangaard Brouer 
3813a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3814a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3815a553e4a6SJamal Hadi Salim #endif
38161da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
381726ad7879SEric Dumazet 	if (pkt_dev->page)
381826ad7879SEric Dumazet 		put_page(pkt_dev->page);
38198788370aSJesper Dangaard Brouer 	kfree_rcu(pkt_dev, rcu);
38201da177e4SLinus Torvalds 	return 0;
38211da177e4SLinus Torvalds }
38221da177e4SLinus Torvalds 
38234e58a027SCong Wang static int __net_init pg_net_init(struct net *net)
38241da177e4SLinus Torvalds {
38254e58a027SCong Wang 	struct pktgen_net *pn = net_generic(net, pg_net_id);
3826d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
38274e58a027SCong Wang 	int cpu, ret = 0;
3828d50a6b56SStephen Hemminger 
38294e58a027SCong Wang 	pn->net = net;
38304e58a027SCong Wang 	INIT_LIST_HEAD(&pn->pktgen_threads);
38314e58a027SCong Wang 	pn->pktgen_exiting = false;
38324e58a027SCong Wang 	pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net);
38334e58a027SCong Wang 	if (!pn->proc_dir) {
38344e58a027SCong Wang 		pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR);
3835d50a6b56SStephen Hemminger 		return -ENODEV;
38361da177e4SLinus Torvalds 	}
38374e58a027SCong Wang 	pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops);
38384e58a027SCong Wang 	if (pe == NULL) {
38394e58a027SCong Wang 		pr_err("cannot create %s procfs entry\n", PGCTRL);
38404e58a027SCong Wang 		ret = -EINVAL;
38414e58a027SCong Wang 		goto remove;
38424e58a027SCong Wang 	}
38431da177e4SLinus Torvalds 
3844670c02c2SJohn Hawkes 	for_each_online_cpu(cpu) {
38458024bb24SLuiz Capitulino 		int err;
38461da177e4SLinus Torvalds 
38474e58a027SCong Wang 		err = pktgen_create_thread(cpu, pn);
38488024bb24SLuiz Capitulino 		if (err)
38494e58a027SCong Wang 			pr_warn("Cannot create thread for cpu %d (%d)\n",
3850f9467eaeSJoe Perches 				   cpu, err);
38511da177e4SLinus Torvalds 	}
38528024bb24SLuiz Capitulino 
38534e58a027SCong Wang 	if (list_empty(&pn->pktgen_threads)) {
38544e58a027SCong Wang 		pr_err("Initialization failed for all threads\n");
3855ce14f894SWANG Cong 		ret = -ENODEV;
38564e58a027SCong Wang 		goto remove_entry;
38578024bb24SLuiz Capitulino 	}
38588024bb24SLuiz Capitulino 
38591da177e4SLinus Torvalds 	return 0;
3860ce14f894SWANG Cong 
38614e58a027SCong Wang remove_entry:
38624e58a027SCong Wang 	remove_proc_entry(PGCTRL, pn->proc_dir);
38634e58a027SCong Wang remove:
3864ece31ffdSGao feng 	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
3865ce14f894SWANG Cong 	return ret;
38661da177e4SLinus Torvalds }
38671da177e4SLinus Torvalds 
38684e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net)
38691da177e4SLinus Torvalds {
38704e58a027SCong Wang 	struct pktgen_net *pn = net_generic(net, pg_net_id);
3871cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3872cdcdbe0bSLuiz Capitulino 	struct list_head *q, *n;
3873d4b11335SEric Dumazet 	LIST_HEAD(list);
38741da177e4SLinus Torvalds 
38751da177e4SLinus Torvalds 	/* Stop all interfaces & threads */
38764e58a027SCong Wang 	pn->pktgen_exiting = true;
38771da177e4SLinus Torvalds 
3878c57b5468SEric Dumazet 	mutex_lock(&pktgen_thread_lock);
38794e58a027SCong Wang 	list_splice_init(&pn->pktgen_threads, &list);
3880c57b5468SEric Dumazet 	mutex_unlock(&pktgen_thread_lock);
3881c57b5468SEric Dumazet 
3882c57b5468SEric Dumazet 	list_for_each_safe(q, n, &list) {
3883cdcdbe0bSLuiz Capitulino 		t = list_entry(q, struct pktgen_thread, th_list);
3884c57b5468SEric Dumazet 		list_del(&t->th_list);
3885ee74baa7SDavid S. Miller 		kthread_stop(t->tsk);
38861fbe4b46SOleg Nesterov 		put_task_struct(t->tsk);
3887ee74baa7SDavid S. Miller 		kfree(t);
38881da177e4SLinus Torvalds 	}
38891da177e4SLinus Torvalds 
38904e58a027SCong Wang 	remove_proc_entry(PGCTRL, pn->proc_dir);
3891ece31ffdSGao feng 	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
38924e58a027SCong Wang }
38931da177e4SLinus Torvalds 
38944e58a027SCong Wang static struct pernet_operations pg_net_ops = {
38954e58a027SCong Wang 	.init = pg_net_init,
38964e58a027SCong Wang 	.exit = pg_net_exit,
38974e58a027SCong Wang 	.id   = &pg_net_id,
38984e58a027SCong Wang 	.size = sizeof(struct pktgen_net),
38994e58a027SCong Wang };
39004e58a027SCong Wang 
39014e58a027SCong Wang static int __init pg_init(void)
39024e58a027SCong Wang {
39034e58a027SCong Wang 	int ret = 0;
39044e58a027SCong Wang 
39054e58a027SCong Wang 	pr_info("%s", version);
39064e58a027SCong Wang 	ret = register_pernet_subsys(&pg_net_ops);
39074e58a027SCong Wang 	if (ret)
39084e58a027SCong Wang 		return ret;
39094e58a027SCong Wang 	ret = register_netdevice_notifier(&pktgen_notifier_block);
39104e58a027SCong Wang 	if (ret)
39114e58a027SCong Wang 		unregister_pernet_subsys(&pg_net_ops);
39124e58a027SCong Wang 
39134e58a027SCong Wang 	return ret;
39144e58a027SCong Wang }
39154e58a027SCong Wang 
39164e58a027SCong Wang static void __exit pg_cleanup(void)
39174e58a027SCong Wang {
39184e58a027SCong Wang 	unregister_netdevice_notifier(&pktgen_notifier_block);
39194e58a027SCong Wang 	unregister_pernet_subsys(&pg_net_ops);
39208788370aSJesper Dangaard Brouer 	/* Don't need rcu_barrier() due to use of kfree_rcu() */
39211da177e4SLinus Torvalds }
39221da177e4SLinus Torvalds 
39231da177e4SLinus Torvalds module_init(pg_init);
39241da177e4SLinus Torvalds module_exit(pg_cleanup);
39251da177e4SLinus Torvalds 
3926c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
39271da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool");
39281da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3929c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION);
39301da177e4SLinus Torvalds module_param(pg_count_d, int, 0);
3931c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
39321da177e4SLinus Torvalds module_param(pg_delay_d, int, 0);
3933c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
39341da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0);
3935c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
39361da177e4SLinus Torvalds module_param(debug, int, 0);
3937c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");
3938