pktgen.c 95.2 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8
/*
 * Authors:
 * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
 *                             Uppsala University and
 *                             Swedish University of Agricultural Sciences
 *
 * Alexey Kuznetsov  <kuznet@ms2.inr.ac.ru>
 * Ben Greear <greearb@candelatech.com>
9
 * Jens Låås <jens.laas@data.slu.se>
Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13 14 15 16 17
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 *
 * A tool for loading the network with preconfigurated packets.
18
 * The tool is implemented as a linux module.  Parameters are output
Linus Torvalds's avatar
Linus Torvalds committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
 * device, delay (to hard_xmit), number of packets, and whether
 * to use multiple SKBs or just the same one.
 * pktgen uses the installed interface's output routine.
 *
 * Additional hacking by:
 *
 * Jens.Laas@data.slu.se
 * Improved by ANK. 010120.
 * Improved by ANK even more. 010212.
 * MAC address typo fixed. 010417 --ro
 * Integrated.  020301 --DaveM
 * Added multiskb option 020301 --DaveM
 * Scaling of results. 020417--sigurdur@linpro.no
 * Significant re-work of the module:
 *   *  Convert to threaded model to more efficiently be able to transmit
 *       and receive on multiple interfaces at once.
 *   *  Converted many counters to __u64 to allow longer runs.
 *   *  Allow configuration of ranges, like min/max IP address, MACs,
 *       and UDP-ports, for both source and destination, and can
 *       set to use a random distribution or sequentially walk the range.
 *   *  Can now change most values after starting.
 *   *  Place 12-byte packet in UDP payload with magic number,
 *       sequence number, and timestamp.
 *   *  Add receiver code that detects dropped pkts, re-ordered pkts, and
 *       latencies (with micro-second) precision.
 *   *  Add IOCTL interface to easily get counters & configuration.
 *   --Ben Greear <greearb@candelatech.com>
 *
47 48
 * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
 * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
Linus Torvalds's avatar
Linus Torvalds committed
49
 * as a "fastpath" with a configurable number of clones after alloc's.
50 51
 * clone_skb=0 means all packets are allocated this also means ranges time
 * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
Linus Torvalds's avatar
Linus Torvalds committed
52 53
 * clones.
 *
54
 * Also moved to /proc/net/pktgen/
Linus Torvalds's avatar
Linus Torvalds committed
55 56 57 58 59 60 61 62
 * --ro
 *
 * Sept 10:  Fixed threading/locking.  Lots of bone-headed and more clever
 *    mistakes.  Also merged in DaveM's patch in the -pre6 patch.
 * --Ben Greear <greearb@candelatech.com>
 *
 * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
 *
63
 *
Linus Torvalds's avatar
Linus Torvalds committed
64 65 66 67
 * 021124 Finished major redesign and rewrite for new functionality.
 * See Documentation/networking/pktgen.txt for how to use this.
 *
 * The new operation:
68 69 70 71
 * For each CPU one thread/process is created at start. This process checks
 * for running devices in the if_list and sends packets until count is 0 it
 * also the thread checks the thread->control which is used for inter-process
 * communication. controlling process "posts" operations to the threads this
72 73 74
 * way.
 * The if_list is RCU protected, and the if_lock remains to protect updating
 * of if_list, from "add_device" as it invoked from userspace (via proc write).
Linus Torvalds's avatar
Linus Torvalds committed
75
 *
76 77
 * By design there should only be *one* "controlling" process. In practice
 * multiple write accesses gives unpredictable result. Understood by "write"
Linus Torvalds's avatar
Linus Torvalds committed
78
 * to /proc gives result code thats should be read be the "writer".
79
 * For practical use this should be no problem.
Linus Torvalds's avatar
Linus Torvalds committed
80
 *
81 82
 * Note when adding devices to a specific CPU there good idea to also assign
 * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU.
Linus Torvalds's avatar
Linus Torvalds committed
83 84
 * --ro
 *
85
 * Fix refcount off by one if first packet fails, potential null deref,
Linus Torvalds's avatar
Linus Torvalds committed
86 87 88 89 90 91 92
 * memleak 030710- KJP
 *
 * First "ranges" functionality for ipv6 030726 --ro
 *
 * Included flow support. 030802 ANK.
 *
 * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
93
 *
Linus Torvalds's avatar
Linus Torvalds committed
94 95 96
 * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
 * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
 *
97
 * New xmit() return, do_div and misc clean up by Stephen Hemminger
Linus Torvalds's avatar
Linus Torvalds committed
98 99
 * <shemminger@osdl.org> 040923
 *
Stephen Hemminger's avatar
Stephen Hemminger committed
100
 * Randy Dunlap fixed u64 printk compiler warning
Linus Torvalds's avatar
Linus Torvalds committed
101 102 103 104
 *
 * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
 * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
 *
105
 * Corrections from Nikolai Malykh (nmalykh@bilim.com)
Linus Torvalds's avatar
Linus Torvalds committed
106 107
 * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
 *
108
 * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
Linus Torvalds's avatar
Linus Torvalds committed
109
 * 050103
110 111 112
 *
 * MPLS support by Steven Whitehouse <steve@chygwyn.com>
 *
Francesco Fondelli's avatar
Francesco Fondelli committed
113 114
 * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
 *
Adit Ranadive's avatar
Adit Ranadive committed
115 116 117
 * Fixed src_mac command to set source mac of packet to value specified in
 * command by Adit Ranadive <adit.262@gmail.com>
 *
Linus Torvalds's avatar
Linus Torvalds committed
118
 */
119 120 121

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Linus Torvalds's avatar
Linus Torvalds committed
122 123 124 125 126
#include <linux/sys.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
127
#include <linux/mutex.h>
Linus Torvalds's avatar
Linus Torvalds committed
128 129 130 131 132 133 134 135 136
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
137
#include <linux/capability.h>
138
#include <linux/hrtimer.h>
139
#include <linux/freezer.h>
Linus Torvalds's avatar
Linus Torvalds committed
140 141
#include <linux/delay.h>
#include <linux/timer.h>
142
#include <linux/list.h>
Linus Torvalds's avatar
Linus Torvalds committed
143 144 145 146 147 148 149
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
Francesco Fondelli's avatar
Francesco Fondelli committed
150
#include <linux/if_vlan.h>
Linus Torvalds's avatar
Linus Torvalds committed
151 152 153 154 155
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/proc_fs.h>
156
#include <linux/seq_file.h>
Linus Torvalds's avatar
Linus Torvalds committed
157
#include <linux/wait.h>
158
#include <linux/etherdevice.h>
159
#include <linux/kthread.h>
160
#include <linux/prefetch.h>
161
#include <net/net_namespace.h>
Linus Torvalds's avatar
Linus Torvalds committed
162 163
#include <net/checksum.h>
#include <net/ipv6.h>
164
#include <net/udp.h>
165
#include <net/ip6_checksum.h>
Linus Torvalds's avatar
Linus Torvalds committed
166
#include <net/addrconf.h>
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
167 168 169
#ifdef CONFIG_XFRM
#include <net/xfrm.h>
#endif
Cong Wang's avatar
Cong Wang committed
170
#include <net/netns/generic.h>
Linus Torvalds's avatar
Linus Torvalds committed
171 172
#include <asm/byteorder.h>
#include <linux/rcupdate.h>
Jiri Slaby's avatar
Jiri Slaby committed
173
#include <linux/bitops.h>
174 175 176
#include <linux/io.h>
#include <linux/timex.h>
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
177
#include <asm/dma.h>
Luiz Capitulino's avatar
Luiz Capitulino committed
178
#include <asm/div64.h>		/* do_div */
Linus Torvalds's avatar
Linus Torvalds committed
179

180
#define VERSION	"2.75"
Linus Torvalds's avatar
Linus Torvalds committed
181
#define IP_NAME_SZ 32
182
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
183
#define MPLS_STACK_BOTTOM htonl(0x00000100)
Linus Torvalds's avatar
Linus Torvalds committed
184

185 186
#define func_enter() pr_debug("entering %s\n", __func__);

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
#define PKT_FLAGS							\
	pf(IPV6)		/* Interface in IPV6 Mode */		\
	pf(IPSRC_RND)		/* IP-Src Random  */			\
	pf(IPDST_RND)		/* IP-Dst Random  */			\
	pf(TXSIZE_RND)		/* Transmit size is random */		\
	pf(UDPSRC_RND)		/* UDP-Src Random */			\
	pf(UDPDST_RND)		/* UDP-Dst Random */			\
	pf(UDPCSUM)		/* Include UDP checksum */		\
	pf(NO_TIMESTAMP)	/* Don't timestamp packets (default TS) */ \
	pf(MPLS_RND)		/* Random MPLS labels */		\
	pf(QUEUE_MAP_RND)	/* queue map Random */			\
	pf(QUEUE_MAP_CPU)	/* queue map mirrors smp_processor_id() */ \
	pf(FLOW_SEQ)		/* Sequential flows */			\
	pf(IPSEC)		/* ipsec on for flows */		\
	pf(MACSRC_RND)		/* MAC-Src Random */			\
	pf(MACDST_RND)		/* MAC-Dst Random */			\
	pf(VID_RND)		/* Random VLAN ID */			\
	pf(SVID_RND)		/* Random SVLAN ID */			\
	pf(NODE)		/* Node memory alloc*/			\

#define pf(flag)		flag##_SHIFT,
enum pkt_flags {
	PKT_FLAGS
};
#undef pf

Linus Torvalds's avatar
Linus Torvalds committed
213
/* Device flag bits */
214 215 216
#define pf(flag)		static const __u32 F_##flag = (1<<flag##_SHIFT);
PKT_FLAGS
#undef pf
Linus Torvalds's avatar
Linus Torvalds committed
217

218 219 220 221 222 223 224 225
#define pf(flag)		__stringify(flag),
static char *pkt_flag_names[] = {
	PKT_FLAGS
};
#undef pf

#define NR_PKT_FLAGS		ARRAY_SIZE(pkt_flag_names)

Linus Torvalds's avatar
Linus Torvalds committed
226
/* Thread control flag bits */
227 228 229 230
#define T_STOP        (1<<0)	/* Stop run */
#define T_RUN         (1<<1)	/* Start run */
#define T_REMDEVALL   (1<<2)	/* Remove all devs */
#define T_REMDEV      (1<<3)	/* Remove one dev */
Linus Torvalds's avatar
Linus Torvalds committed
231

232 233 234
/* Xmit modes */
#define M_START_XMIT		0	/* Default normal TX */
#define M_NETIF_RECEIVE 	1	/* Inject packets into stack */
235
#define M_QUEUE_XMIT		2	/* Inject packet into qdisc */
236

237
/* If lock -- protects updating of if_list */
238 239
#define   if_lock(t)           mutex_lock(&(t->if_lock));
#define   if_unlock(t)           mutex_unlock(&(t->if_lock));
Linus Torvalds's avatar
Linus Torvalds committed
240 241 242

/* Used to help with determining the pkts on receive */
#define PKTGEN_MAGIC 0xbe9be955
243 244
#define PG_PROC_DIR "pktgen"
#define PGCTRL	    "pgctrl"
Linus Torvalds's avatar
Linus Torvalds committed
245 246 247

#define MAX_CFLOWS  65536

Francesco Fondelli's avatar
Francesco Fondelli committed
248 249 250
#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)

Luiz Capitulino's avatar
Luiz Capitulino committed
251
struct flow_state {
Al Viro's avatar
Al Viro committed
252
	__be32 cur_daddr;
Luiz Capitulino's avatar
Luiz Capitulino committed
253
	int count;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
254 255 256
#ifdef CONFIG_XFRM
	struct xfrm_state *x;
#endif
257
	__u32 flags;
Linus Torvalds's avatar
Linus Torvalds committed
258 259
};

260 261 262
/* flow flag bits */
#define F_INIT   (1<<0)		/* flow has been initialized */

Linus Torvalds's avatar
Linus Torvalds committed
263 264 265 266
struct pktgen_dev {
	/*
	 * Try to keep frequent/infrequent used vars. separated.
	 */
267 268
	struct proc_dir_entry *entry;	/* proc file */
	struct pktgen_thread *pg_thread;/* the owner */
269
	struct list_head list;		/* chaining in the thread's run-queue */
270
	struct rcu_head	 rcu;		/* freed by RCU */
Linus Torvalds's avatar
Linus Torvalds committed
271

272
	int running;		/* if false, the test will stop */
Linus Torvalds's avatar
Linus Torvalds committed
273

Luiz Capitulino's avatar
Luiz Capitulino committed
274 275 276 277
	/* If min != max, then we will either do a linear iteration, or
	 * we will do a random selection from within the range.
	 */
	__u32 flags;
278
	int xmit_mode;
279 280
	int min_pkt_size;
	int max_pkt_size;
281
	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
Luiz Capitulino's avatar
Luiz Capitulino committed
282
	int nfrags;
283 284 285
	int removal_mark;	/* non-zero => the device is marked for
				 * removal by worker thread */

286
	struct page *page;
287 288
	u64 delay;		/* nano-seconds */

Luiz Capitulino's avatar
Luiz Capitulino committed
289 290 291
	__u64 count;		/* Default No packets to send */
	__u64 sofar;		/* How many pkts we've sent so far */
	__u64 tx_bytes;		/* How many bytes we've transmitted */
292
	__u64 errors;		/* Errors when trying to transmit, */
Luiz Capitulino's avatar
Luiz Capitulino committed
293 294 295 296 297

	/* runtime counters relating to clone_skb */

	__u32 clone_count;
	int last_ok;		/* Was last skb sent?
298 299
				 * Or a failed transmit of some sort?
				 * This will keep sequence numbers in order
Luiz Capitulino's avatar
Luiz Capitulino committed
300
				 */
301 302 303 304 305
	ktime_t next_tx;
	ktime_t started_at;
	ktime_t stopped_at;
	u64	idle_acc;	/* nano-seconds */

Luiz Capitulino's avatar
Luiz Capitulino committed
306 307
	__u32 seq_num;

308 309 310 311 312 313 314 315
	int clone_skb;		/*
				 * Use multiple SKBs during packet gen.
				 * If this number is greater than 1, then
				 * that many copies of the same packet will be
				 * sent before a new packet is allocated.
				 * If you want to send 1024 identical packets
				 * before creating a new packet,
				 * set clone_skb to 1024.
Luiz Capitulino's avatar
Luiz Capitulino committed
316 317 318 319 320 321 322 323 324 325 326
				 */

	char dst_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
	char dst_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
	char src_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
	char src_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */

	struct in6_addr in6_saddr;
	struct in6_addr in6_daddr;
	struct in6_addr cur_in6_daddr;
	struct in6_addr cur_in6_saddr;
Linus Torvalds's avatar
Linus Torvalds committed
327
	/* For ranges */
Luiz Capitulino's avatar
Luiz Capitulino committed
328 329 330 331 332 333 334 335
	struct in6_addr min_in6_daddr;
	struct in6_addr max_in6_daddr;
	struct in6_addr min_in6_saddr;
	struct in6_addr max_in6_saddr;

	/* If we're doing ranges, random or incremental, then this
	 * defines the min/max for those ranges.
	 */
Al Viro's avatar
Al Viro committed
336 337 338 339
	__be32 saddr_min;	/* inclusive, source IP address */
	__be32 saddr_max;	/* exclusive, source IP address */
	__be32 daddr_min;	/* inclusive, dest IP address */
	__be32 daddr_max;	/* exclusive, dest IP address */
Luiz Capitulino's avatar
Luiz Capitulino committed
340 341 342 343 344 345

	__u16 udp_src_min;	/* inclusive, source UDP port */
	__u16 udp_src_max;	/* exclusive, source UDP port */
	__u16 udp_dst_min;	/* inclusive, dest UDP port */
	__u16 udp_dst_max;	/* exclusive, dest UDP port */

Francesco Fondelli's avatar
Francesco Fondelli committed
346
	/* DSCP + ECN */
347 348 349 350
	__u8 tos;            /* six MSB of (former) IPv4 TOS
				are for dscp codepoint */
	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6
				(see RFC 3260, sec. 4) */
Francesco Fondelli's avatar
Francesco Fondelli committed
351

352
	/* MPLS */
353
	unsigned int nr_labels;	/* Depth of stack, 0 = no MPLS */
354 355
	__be32 labels[MAX_MPLS_LABELS];

Francesco Fondelli's avatar
Francesco Fondelli committed
356 357 358 359 360 361 362 363 364
	/* VLAN/SVLAN (802.1Q/Q-in-Q) */
	__u8  vlan_p;
	__u8  vlan_cfi;
	__u16 vlan_id;  /* 0xffff means no vlan tag */

	__u8  svlan_p;
	__u8  svlan_cfi;
	__u16 svlan_id; /* 0xffff means no svlan tag */

Luiz Capitulino's avatar
Luiz Capitulino committed
365 366 367 368 369 370 371 372
	__u32 src_mac_count;	/* How many MACs to iterate through */
	__u32 dst_mac_count;	/* How many MACs to iterate through */

	unsigned char dst_mac[ETH_ALEN];
	unsigned char src_mac[ETH_ALEN];

	__u32 cur_dst_mac_offset;
	__u32 cur_src_mac_offset;
Al Viro's avatar
Al Viro committed
373 374
	__be32 cur_saddr;
	__be32 cur_daddr;
375
	__u16 ip_id;
Luiz Capitulino's avatar
Luiz Capitulino committed
376 377
	__u16 cur_udp_dst;
	__u16 cur_udp_src;
378
	__u16 cur_queue_map;
Luiz Capitulino's avatar
Luiz Capitulino committed
379
	__u32 cur_pkt_size;
380
	__u32 last_pkt_size;
Luiz Capitulino's avatar
Luiz Capitulino committed
381 382 383 384 385 386 387 388 389 390 391 392

	__u8 hh[14];
	/* = {
	   0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,

	   We fill in SRC address later
	   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	   0x08, 0x00
	   };
	 */
	__u16 pad;		/* pad out the hh struct to an even 16 bytes */

393
	struct sk_buff *skb;	/* skb we are to transmit next, used for when we
Luiz Capitulino's avatar
Luiz Capitulino committed
394 395
				 * are transmitting the same one multiple times
				 */
396 397 398 399 400 401 402 403
	struct net_device *odev; /* The out-going device.
				  * Note that the device should have it's
				  * pg_info pointer pointing back to this
				  * device.
				  * Set when the user specifies the out-going
				  * device name (not when the inject is
				  * started as it used to do.)
				  */
404
	char odevname[32];
Linus Torvalds's avatar
Linus Torvalds committed
405
	struct flow_state *flows;
406 407 408 409
	unsigned int cflows;	/* Concurrent flows (config) */
	unsigned int lflow;		/* Flow length  (config) */
	unsigned int nflows;	/* accumulated flows (stats) */
	unsigned int curfl;		/* current sequenced flow (state)*/
410 411 412

	u16 queue_map_min;
	u16 queue_map_max;
413
	__u32 skb_priority;	/* skb priority field */
414
	unsigned int burst;	/* number of duplicated packets to burst */
Robert Olsson's avatar
Robert Olsson committed
415
	int node;               /* Memory node */
416

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
417 418 419
#ifdef CONFIG_XFRM
	__u8	ipsmode;		/* IPSEC mode (config) */
	__u8	ipsproto;		/* IPSEC type (config) */
420
	__u32	spi;
421
	struct xfrm_dst xdst;
422
	struct dst_ops dstops;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
423
#endif
424
	char result[512];
Linus Torvalds's avatar
Linus Torvalds committed
425 426 427
};

struct pktgen_hdr {
Al Viro's avatar
Al Viro committed
428 429 430 431
	__be32 pgh_magic;
	__be32 seq_num;
	__be32 tv_sec;
	__be32 tv_usec;
Linus Torvalds's avatar
Linus Torvalds committed
432 433
};

Cong Wang's avatar
Cong Wang committed
434

435
static unsigned int pg_net_id __read_mostly;
Cong Wang's avatar
Cong Wang committed
436 437 438 439 440 441 442

struct pktgen_net {
	struct net		*net;
	struct proc_dir_entry	*proc_dir;
	struct list_head	pktgen_threads;
	bool			pktgen_exiting;
};
443

Linus Torvalds's avatar
Linus Torvalds committed
444
struct pktgen_thread {
445
	struct mutex if_lock;		/* for list of devices */
446
	struct list_head if_list;	/* All device here */
447
	struct list_head th_list;
448
	struct task_struct *tsk;
Luiz Capitulino's avatar
Luiz Capitulino committed
449 450
	char result[512];

451 452
	/* Field for thread to receive "posted" events terminate,
	   stop ifs etc. */
Luiz Capitulino's avatar
Luiz Capitulino committed
453 454

	u32 control;
Linus Torvalds's avatar
Linus Torvalds committed
455 456
	int cpu;

Luiz Capitulino's avatar
Luiz Capitulino committed
457
	wait_queue_head_t queue;
458
	struct completion start_done;
Cong Wang's avatar
Cong Wang committed
459
	struct pktgen_net *net;
Linus Torvalds's avatar
Linus Torvalds committed
460 461 462 463 464
};

#define REMOVE 1
#define FIND   0

Stephen Hemminger's avatar
Stephen Hemminger committed
465
static const char version[] =
466 467
	"Packet Generator for packet performance testing. "
	"Version: " VERSION "\n";
Linus Torvalds's avatar
Linus Torvalds committed
468

Luiz Capitulino's avatar
Luiz Capitulino committed
469 470 471
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
472
					  const char *ifname, bool exact);
Linus Torvalds's avatar
Linus Torvalds committed
473
static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
Cong Wang's avatar
Cong Wang committed
474 475 476
static void pktgen_run_all_threads(struct pktgen_net *pn);
static void pktgen_reset_all_threads(struct pktgen_net *pn);
static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn);
477

Luiz Capitulino's avatar
Luiz Capitulino committed
478
static void pktgen_stop(struct pktgen_thread *t);
Linus Torvalds's avatar
Linus Torvalds committed
479
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
480

Linus Torvalds's avatar
Linus Torvalds committed
481
/* Module parameters, defaults. */
482 483 484 485
static int pg_count_d __read_mostly = 1000;
static int pg_delay_d __read_mostly;
static int pg_clone_skb_d  __read_mostly;
static int debug  __read_mostly;
Linus Torvalds's avatar
Linus Torvalds committed
486

487
static DEFINE_MUTEX(pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
488 489 490 491 492 493

static struct notifier_block pktgen_notifier_block = {
	.notifier_call = pktgen_device_event,
};

/*
494
 * /proc handling functions
Linus Torvalds's avatar
Linus Torvalds committed
495 496 497
 *
 */

498
static int pgctrl_show(struct seq_file *seq, void *v)
Luiz Capitulino's avatar
Luiz Capitulino committed
499
{
Stephen Hemminger's avatar
Stephen Hemminger committed
500
	seq_puts(seq, version);
501
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
502 503
}

504 505
static ssize_t pgctrl_write(struct file *file, const char __user *buf,
			    size_t count, loff_t *ppos)
Linus Torvalds's avatar
Linus Torvalds committed
506
{
507
	char data[128];
Cong Wang's avatar
Cong Wang committed
508
	struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
Linus Torvalds's avatar
Linus Torvalds committed
509

510 511
	if (!capable(CAP_NET_ADMIN))
		return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
512

513 514 515
	if (count == 0)
		return -EINVAL;

516 517
	if (count > sizeof(data))
		count = sizeof(data);
Linus Torvalds's avatar
Linus Torvalds committed
518

519 520 521
	if (copy_from_user(data, buf, count))
		return -EFAULT;

522
	data[count - 1] = 0;	/* Strip trailing '\n' and terminate string */
Linus Torvalds's avatar
Linus Torvalds committed
523

Luiz Capitulino's avatar
Luiz Capitulino committed
524
	if (!strcmp(data, "stop"))
Cong Wang's avatar
Cong Wang committed
525
		pktgen_stop_all_threads_ifs(pn);
Linus Torvalds's avatar
Linus Torvalds committed
526

Luiz Capitulino's avatar
Luiz Capitulino committed
527
	else if (!strcmp(data, "start"))
Cong Wang's avatar
Cong Wang committed
528
		pktgen_run_all_threads(pn);
Linus Torvalds's avatar
Linus Torvalds committed
529

530
	else if (!strcmp(data, "reset"))
Cong Wang's avatar
Cong Wang committed
531
		pktgen_reset_all_threads(pn);
532

Luiz Capitulino's avatar
Luiz Capitulino committed
533
	else
534
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
535

536
	return count;
Linus Torvalds's avatar
Linus Torvalds committed
537 538
}

539 540
static int pgctrl_open(struct inode *inode, struct file *file)
{
541
	return single_open(file, pgctrl_show, PDE_DATA(inode));
542 543
}

544
static const struct file_operations pktgen_fops = {
Luiz Capitulino's avatar
Luiz Capitulino committed
545 546 547 548 549
	.open    = pgctrl_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pgctrl_write,
	.release = single_release,
550 551 552
};

static int pktgen_if_show(struct seq_file *seq, void *v)
Linus Torvalds's avatar
Linus Torvalds committed
553
{
Stephen Hemminger's avatar
Stephen Hemminger committed
554
	const struct pktgen_dev *pkt_dev = seq->private;
555
	ktime_t stopped;
556
	unsigned int i;
557
	u64 idle;
Luiz Capitulino's avatar
Luiz Capitulino committed
558 559 560 561 562 563 564

	seq_printf(seq,
		   "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
		   (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size,
		   pkt_dev->max_pkt_size);

	seq_printf(seq,
565 566
		   "     frags: %d  delay: %llu  clone_skb: %d  ifname: %s\n",
		   pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
567
		   pkt_dev->clone_skb, pkt_dev->odevname);
Luiz Capitulino's avatar
Luiz Capitulino committed
568 569 570 571

	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
		   pkt_dev->lflow);

572 573 574 575 576
	seq_printf(seq,
		   "     queue_map_min: %u  queue_map_max: %u\n",
		   pkt_dev->queue_map_min,
		   pkt_dev->queue_map_max);

577 578 579 580
	if (pkt_dev->skb_priority)
		seq_printf(seq, "     skb_priority: %u\n",
			   pkt_dev->skb_priority);

Luiz Capitulino's avatar
Luiz Capitulino committed
581 582
	if (pkt_dev->flags & F_IPV6) {
		seq_printf(seq,
583 584 585 586 587 588
			   "     saddr: %pI6c  min_saddr: %pI6c  max_saddr: %pI6c\n"
			   "     daddr: %pI6c  min_daddr: %pI6c  max_daddr: %pI6c\n",
			   &pkt_dev->in6_saddr,
			   &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr,
			   &pkt_dev->in6_daddr,
			   &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr);
589 590 591 592
	} else {
		seq_printf(seq,
			   "     dst_min: %s  dst_max: %s\n",
			   pkt_dev->dst_min, pkt_dev->dst_max);
Luiz Capitulino's avatar
Luiz Capitulino committed
593
		seq_printf(seq,
594
			   "     src_min: %s  src_max: %s\n",
595 596
			   pkt_dev->src_min, pkt_dev->src_max);
	}
Linus Torvalds's avatar
Linus Torvalds committed
597

Luiz Capitulino's avatar
Luiz Capitulino committed
598
	seq_puts(seq, "     src_mac: ");
Linus Torvalds's avatar
Linus Torvalds committed
599

600 601 602
	seq_printf(seq, "%pM ",
		   is_zero_ether_addr(pkt_dev->src_mac) ?
			     pkt_dev->odev->dev_addr : pkt_dev->src_mac);
Luiz Capitulino's avatar
Luiz Capitulino committed
603

604
	seq_puts(seq, "dst_mac: ");
605
	seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
Luiz Capitulino's avatar
Luiz Capitulino committed
606 607

	seq_printf(seq,
608 609
		   "     udp_src_min: %d  udp_src_max: %d"
		   "  udp_dst_min: %d  udp_dst_max: %d\n",
Luiz Capitulino's avatar
Luiz Capitulino committed
610 611 612 613
		   pkt_dev->udp_src_min, pkt_dev->udp_src_max,
		   pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);

	seq_printf(seq,
614
		   "     src_mac_count: %d  dst_mac_count: %d\n",
Luiz Capitulino's avatar
Luiz Capitulino committed
615
		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
Linus Torvalds's avatar
Linus Torvalds committed
616

617
	if (pkt_dev->nr_labels) {
618
		seq_puts(seq, "     mpls: ");
619
		for (i = 0; i < pkt_dev->nr_labels; i++)
620 621 622 623
			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
	}

624
	if (pkt_dev->vlan_id != 0xffff)
Francesco Fondelli's avatar
Francesco Fondelli committed
625
		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
626 627
			   pkt_dev->vlan_id, pkt_dev->vlan_p,
			   pkt_dev->vlan_cfi);
Francesco Fondelli's avatar
Francesco Fondelli committed
628

629
	if (pkt_dev->svlan_id != 0xffff)
Francesco Fondelli's avatar
Francesco Fondelli committed
630
		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
631 632
			   pkt_dev->svlan_id, pkt_dev->svlan_p,
			   pkt_dev->svlan_cfi);
Francesco Fondelli's avatar
Francesco Fondelli committed
633

634
	if (pkt_dev->tos)
Francesco Fondelli's avatar
Francesco Fondelli committed
635 636
		seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);

637
	if (pkt_dev->traffic_class)
Francesco Fondelli's avatar
Francesco Fondelli committed
638 639
		seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);

640 641 642
	if (pkt_dev->burst > 1)
		seq_printf(seq, "     burst: %d\n", pkt_dev->burst);

Robert Olsson's avatar
Robert Olsson committed
643 644 645
	if (pkt_dev->node >= 0)
		seq_printf(seq, "     node: %d\n", pkt_dev->node);

646 647
	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
		seq_puts(seq, "     xmit_mode: netif_receive\n");
648 649
	else if (pkt_dev->xmit_mode == M_QUEUE_XMIT)
		seq_puts(seq, "     xmit_mode: xmit_queue\n");
650

651
	seq_puts(seq, "     Flags: ");
652

653 654 655 656
	for (i = 0; i < NR_PKT_FLAGS; i++) {
		if (i == F_FLOW_SEQ)
			if (!pkt_dev->cflows)
				continue;
657

658 659 660 661
		if (pkt_dev->flags & (1 << i))
			seq_printf(seq, "%s  ", pkt_flag_names[i]);
		else if (i == F_FLOW_SEQ)
			seq_puts(seq, "FLOW_RND  ");
662

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
663
#ifdef CONFIG_XFRM
664
		if (i == F_IPSEC && pkt_dev->spi)
665
			seq_printf(seq, "spi:%u", pkt_dev->spi);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
666
#endif
667
	}
Robert Olsson's avatar
Robert Olsson committed
668

Luiz Capitulino's avatar
Luiz Capitulino committed
669 670
	seq_puts(seq, "\n");

671
	/* not really stopped, more like last-running-at */
672
	stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at;
673 674
	idle = pkt_dev->idle_acc;
	do_div(idle, NSEC_PER_USEC);
Linus Torvalds's avatar
Linus Torvalds committed
675

Luiz Capitulino's avatar
Luiz Capitulino committed
676
	seq_printf(seq,
677
		   "Current:\n     pkts-sofar: %llu  errors: %llu\n",
Luiz Capitulino's avatar
Luiz Capitulino committed
678
		   (unsigned long long)pkt_dev->sofar,
679 680 681 682 683 684 685
		   (unsigned long long)pkt_dev->errors);

	seq_printf(seq,
		   "     started: %lluus  stopped: %lluus idle: %lluus\n",
		   (unsigned long long) ktime_to_us(pkt_dev->started_at),
		   (unsigned long long) ktime_to_us(stopped),
		   (unsigned long long) idle);
Linus Torvalds's avatar
Linus Torvalds committed
686

Luiz Capitulino's avatar
Luiz Capitulino committed
687 688
	seq_printf(seq,
		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
689 690
		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
		   pkt_dev->cur_src_mac_offset);
Linus Torvalds's avatar
Linus Torvalds committed
691

Luiz Capitulino's avatar
Luiz Capitulino committed
692
	if (pkt_dev->flags & F_IPV6) {
693 694 695
		seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
				&pkt_dev->cur_in6_saddr,
				&pkt_dev->cur_in6_daddr);
Luiz Capitulino's avatar
Luiz Capitulino committed
696
	} else
697 698
		seq_printf(seq, "     cur_saddr: %pI4  cur_daddr: %pI4\n",
			   &pkt_dev->cur_saddr, &pkt_dev->cur_daddr);
Linus Torvalds's avatar
Linus Torvalds committed
699

Luiz Capitulino's avatar
Luiz Capitulino committed
700
	seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
701
		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
Linus Torvalds's avatar
Linus Torvalds committed
702

703 704
	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);

Luiz Capitulino's avatar
Luiz Capitulino committed
705
	seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
Linus Torvalds's avatar
Linus Torvalds committed
706 707

	if (pkt_dev->result[0])
Luiz Capitulino's avatar
Luiz Capitulino committed
708
		seq_printf(seq, "Result: %s\n", pkt_dev->result);
Linus Torvalds's avatar
Linus Torvalds committed
709
	else
710
		seq_puts(seq, "Result: Idle\n");
Linus Torvalds's avatar
Linus Torvalds committed
711

712
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
713 714
}

715

716 717
static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
		     __u32 *num)
718 719 720 721
{
	int i = 0;
	*num = 0;

722
	for (; i < maxlen; i++) {
723
		int value;
724 725 726 727
		char c;
		*num <<= 4;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
728 729 730
		value = hex_to_bin(c);
		if (value >= 0)
			*num |= value;
731 732 733 734 735 736
		else
			break;
	}
	return i;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
737 738
static int count_trail_chars(const char __user * user_buffer,
			     unsigned int maxlen)
Linus Torvalds's avatar
Linus Torvalds committed
739 740 741 742
{
	int i;

	for (i = 0; i < maxlen; i++) {
Luiz Capitulino's avatar
Luiz Capitulino committed
743 744 745 746
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
Linus Torvalds's avatar
Linus Torvalds committed
747 748 749 750 751 752 753 754 755
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
		case '=':
			break;
		default:
			goto done;
756
		}
Linus Torvalds's avatar
Linus Torvalds committed
757 758 759 760 761
	}
done:
	return i;
}

762 763
static long num_arg(const char __user *user_buffer, unsigned long maxlen,
				unsigned long *num)
Linus Torvalds's avatar
Linus Torvalds committed
764
{
765
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
766
	*num = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
767

768
	for (i = 0; i < maxlen; i++) {
Luiz Capitulino's avatar
Luiz Capitulino committed
769 770 771 772
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		if ((c >= '0') && (c <= '9')) {
Linus Torvalds's avatar
Linus Torvalds committed
773
			*num *= 10;
Luiz Capitulino's avatar
Luiz Capitulino committed
774
			*num += c - '0';
Linus Torvalds's avatar
Linus Torvalds committed
775 776 777 778 779 780
		} else
			break;
	}
	return i;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
781
static int strn_len(const char __user * user_buffer, unsigned int maxlen)
Linus Torvalds's avatar
Linus Torvalds committed
782
{
783
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
784

785
	for (i = 0; i < maxlen; i++) {
Luiz Capitulino's avatar
Luiz Capitulino committed
786 787 788 789
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
Linus Torvalds's avatar
Linus Torvalds committed
790 791 792 793 794 795 796 797
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
			goto done_str;
		default:
			break;
798
		}
Linus Torvalds's avatar
Linus Torvalds committed
799 800 801 802 803
	}
done_str:
	return i;
}

804 805
static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
{
806
	unsigned int n = 0;
807 808 809 810 811 812 813
	char c;
	ssize_t i = 0;
	int len;

	pkt_dev->nr_labels = 0;
	do {
		__u32 tmp;
Francesco Fondelli's avatar
Francesco Fondelli committed
814
		len = hex32_arg(&buffer[i], 8, &tmp);
815 816 817 818 819 820 821 822 823 824 825 826
		if (len <= 0)
			return len;
		pkt_dev->labels[n] = htonl(tmp);
		if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
			pkt_dev->flags |= F_MPLS_RND;
		i += len;
		if (get_user(c, &buffer[i]))
			return -EFAULT;
		i++;
		n++;
		if (n >= MAX_MPLS_LABELS)
			return -E2BIG;
827
	} while (c == ',');
828 829 830 831 832

	pkt_dev->nr_labels = n;
	return i;
}

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
static __u32 pktgen_read_flag(const char *f, bool *disable)
{
	__u32 i;

	if (f[0] == '!') {
		*disable = true;
		f++;
	}

	for (i = 0; i < NR_PKT_FLAGS; i++) {
		if (!IS_ENABLED(CONFIG_XFRM) && i == IPSEC_SHIFT)
			continue;

		/* allow only disabling ipv6 flag */
		if (!*disable && i == IPV6_SHIFT)
			continue;

		if (strcmp(f, pkt_flag_names[i]) == 0)
			return 1 << i;
	}

	if (strcmp(f, "FLOW_RND") == 0) {
		*disable = !*disable;
		return F_FLOW_SEQ;
	}

	return 0;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
862 863 864
static ssize_t pktgen_if_write(struct file *file,
			       const char __user * user_buffer, size_t count,
			       loff_t * offset)
Linus Torvalds's avatar
Linus Torvalds committed
865
{
866
	struct seq_file *seq = file->private_data;
Luiz Capitulino's avatar
Luiz Capitulino committed
867
	struct pktgen_dev *pkt_dev = seq->private;
868
	int i, max, len;
Linus Torvalds's avatar
Linus Torvalds committed
869 870
	char name[16], valstr[32];
	unsigned long value = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
871 872
	char *pg_result = NULL;
	int tmp = 0;
Linus Torvalds's avatar
Linus Torvalds committed
873
	char buf[128];
Luiz Capitulino's avatar
Luiz Capitulino committed
874 875 876

	pg_result = &(pkt_dev->result[0]);

Linus Torvalds's avatar
Linus Torvalds committed
877
	if (count < 1) {
878
		pr_warn("wrong command format\n");
Linus Torvalds's avatar
Linus Torvalds committed
879 880
		return -EINVAL;
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
881

882 883
	max = count;
	tmp = count_trail_chars(user_buffer, max);
Luiz Capitulino's avatar
Luiz Capitulino committed
884
	if (tmp < 0) {
885
		pr_warn("illegal format\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
886
		return tmp;
Linus Torvalds's avatar
Linus Torvalds committed
887
	}
888
	i = tmp;
Luiz Capitulino's avatar
Luiz Capitulino committed
889

Linus Torvalds's avatar
Linus Torvalds committed
890 891 892
	/* Read variable name */

	len = strn_len(&user_buffer[i], sizeof(name) - 1);
893
	if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
894
		return len;
895

Linus Torvalds's avatar
Linus Torvalds committed
896
	memset(name, 0, sizeof(name));
Luiz Capitulino's avatar
Luiz Capitulino committed
897
	if (copy_from_user(name, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
898 899
		return -EFAULT;
	i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
900 901

	max = count - i;
Linus Torvalds's avatar
Linus Torvalds committed
902
	len = count_trail_chars(&user_buffer[i], max);
Luiz Capitulino's avatar
Luiz Capitulino committed
903 904 905
	if (len < 0)
		return len;

Linus Torvalds's avatar
Linus Torvalds committed
906 907 908
	i += len;

	if (debug) {
909
		size_t copy = min_t(size_t, count, 1023);
910 911
		char tb[copy + 1];
		if (copy_from_user(tb, user_buffer, copy))
Linus Torvalds's avatar
Linus Torvalds committed
912
			return -EFAULT;
913
		tb[copy] = 0;
Joe Perches's avatar
Joe Perches committed
914 915
		pr_debug("%s,%lu  buffer -:%s:-\n",
			 name, (unsigned long)count, tb);
Luiz Capitulino's avatar
Luiz Capitulino committed
916
	}
Linus Torvalds's avatar
Linus Torvalds committed
917 918 919

	if (!strcmp(name, "min_pkt_size")) {
		len = num_arg(&user_buffer[i], 10, &value);
920
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
921
			return len;
922

Linus Torvalds's avatar
Linus Torvalds committed
923
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
924 925 926 927 928 929 930 931
		if (value < 14 + 20 + 8)
			value = 14 + 20 + 8;
		if (value != pkt_dev->min_pkt_size) {
			pkt_dev->min_pkt_size = value;
			pkt_dev->cur_pkt_size = value;
		}
		sprintf(pg_result, "OK: min_pkt_size=%u",
			pkt_dev->min_pkt_size);
Linus Torvalds's avatar
Linus Torvalds committed
932 933 934
		return count;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
935
	if (!strcmp(name, "max_pkt_size")) {
Linus Torvalds's avatar
Linus Torvalds committed
936
		len = num_arg(&user_buffer[i], 10, &value);
937
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
938
			return len;
939

Linus Torvalds's avatar
Linus Torvalds committed
940
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
941 942 943 944 945 946 947 948
		if (value < 14 + 20 + 8)
			value = 14 + 20 + 8;
		if (value != pkt_dev->max_pkt_size) {
			pkt_dev->max_pkt_size = value;
			pkt_dev->cur_pkt_size = value;
		}
		sprintf(pg_result, "OK: max_pkt_size=%u",
			pkt_dev->max_pkt_size);
Linus Torvalds's avatar
Linus Torvalds committed
949 950 951
		return count;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
952
	/* Shortcut for min = max */
Linus Torvalds's avatar
Linus Torvalds committed
953 954 955

	if (!strcmp(name, "pkt_size")) {
		len = num_arg(&user_buffer[i], 10, &value);
956
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
957
			return len;
958

Linus Torvalds's avatar
Linus Torvalds committed
959
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
960 961 962 963 964 965 966
		if (value < 14 + 20 + 8)
			value = 14 + 20 + 8;
		if (value != pkt_dev->min_pkt_size) {
			pkt_dev->min_pkt_size = value;
			pkt_dev->max_pkt_size = value;
			pkt_dev->cur_pkt_size = value;
		}
Linus Torvalds's avatar
Linus Torvalds committed
967 968 969 970
		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
		return count;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
971
	if (!strcmp(name, "debug")) {
Linus Torvalds's avatar
Linus Torvalds committed
972
		len = num_arg(&user_buffer[i], 10, &value);
973
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
974
			return len;
975

Linus Torvalds's avatar
Linus Torvalds committed
976
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
977
		debug = value;
Linus Torvalds's avatar
Linus Torvalds committed
978 979 980 981
		sprintf(pg_result, "OK: debug=%u", debug);
		return count;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
982
	if (!strcmp(name, "frags")) {
Linus Torvalds's avatar
Linus Torvalds committed
983
		len = num_arg(&user_buffer[i], 10, &value);
984
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
985
			return len;
986

Linus Torvalds's avatar
Linus Torvalds committed
987 988 989 990 991 992 993
		i += len;
		pkt_dev->nfrags = value;
		sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
		return count;
	}
	if (!strcmp(name, "delay")) {
		len = num_arg(&user_buffer[i], 10, &value);
994
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
995
			return len;
996

Linus Torvalds's avatar
Linus Torvalds committed
997
		i += len;
998 999 1000
		if (value == 0x7FFFFFFF)
			pkt_dev->delay = ULLONG_MAX;
		else
1001
			pkt_dev->delay = (u64)value;
1002 1003 1004

		sprintf(pg_result, "OK: delay=%llu",
			(unsigned long long) pkt_dev->delay);
Linus Torvalds's avatar
Linus Torvalds committed
1005 1006
		return count;
	}
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
	if (!strcmp(name, "rate")) {
		len = num_arg(&user_buffer[i], 10, &value);
		if (len < 0)
			return len;

		i += len;
		if (!value)
			return len;
		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
		if (debug)
1017
			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031

		sprintf(pg_result, "OK: rate=%lu", value);
		return count;
	}
	if (!strcmp(name, "ratep")) {
		len = num_arg(&user_buffer[i], 10, &value);
		if (len < 0)
			return len;

		i += len;
		if (!value)
			return len;
		pkt_dev->delay = NSEC_PER_SEC/value;
		if (debug)
1032
			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
1033 1034 1035 1036

		sprintf(pg_result, "OK: rate=%lu", value);
		return count;
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
1037
	if (!strcmp(name, "udp_src_min")) {
Linus Torvalds's avatar
Linus Torvalds committed
1038
		len = num_arg(&user_buffer[i], 10, &value);
1039
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1040
			return len;
1041

Linus Torvalds's avatar
Linus Torvalds committed
1042
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1043 1044 1045 1046
		if (value != pkt_dev->udp_src_min) {
			pkt_dev->udp_src_min = value;
			pkt_dev->cur_udp_src = value;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1047 1048 1049
		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
		return count;
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
1050
	if (!strcmp(name, "udp_dst_min")) {
Linus Torvalds's avatar
Linus Torvalds committed
1051
		len = num_arg(&user_buffer[i], 10, &value);
1052
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1053
			return len;
1054

Linus Torvalds's avatar
Linus Torvalds committed
1055
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1056 1057 1058 1059
		if (value != pkt_dev->udp_dst_min) {
			pkt_dev->udp_dst_min = value;
			pkt_dev->cur_udp_dst = value;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1060 1061 1062
		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
		return count;
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
1063
	if (!strcmp(name, "udp_src_max")) {
Linus Torvalds's avatar
Linus Torvalds committed
1064
		len = num_arg(&user_buffer[i], 10, &value);
1065
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1066
			return len;
1067

Linus Torvalds's avatar
Linus Torvalds committed
1068
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1069 1070 1071 1072
		if (value != pkt_dev->udp_src_max) {
			pkt_dev->udp_src_max = value;
			pkt_dev->cur_udp_src = value;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1073 1074 1075
		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
		return count;
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
1076
	if (!strcmp(name, "udp_dst_max")) {
Linus Torvalds's avatar
Linus Torvalds committed
1077
		len = num_arg(&user_buffer[i], 10, &value);
1078
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1079
			return len;
1080

Linus Torvalds's avatar
Linus Torvalds committed
1081
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1082 1083 1084 1085
		if (value != pkt_dev->udp_dst_max) {
			pkt_dev->udp_dst_max = value;
			pkt_dev->cur_udp_dst = value;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1086 1087 1088 1089 1090
		sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
		return count;
	}
	if (!strcmp(name, "clone_skb")) {
		len = num_arg(&user_buffer[i], 10, &value);
1091
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1092
			return len;
1093
		if ((value > 0) &&
1094 1095
		    ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) ||
		     !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
1096
			return -ENOTSUPP;
Linus Torvalds's avatar
Linus Torvalds committed
1097
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1098 1099
		pkt_dev->clone_skb = value;

Linus Torvalds's avatar
Linus Torvalds committed
1100 1101 1102 1103 1104
		sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
		return count;
	}
	if (!strcmp(name, "count")) {
		len = num_arg(&user_buffer[i], 10, &value);
1105
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1106
			return len;
1107

Linus Torvalds's avatar
Linus Torvalds committed
1108 1109 1110
		i += len;
		pkt_dev->count = value;
		sprintf(pg_result, "OK: count=%llu",
Luiz Capitulino's avatar
Luiz Capitulino committed
1111
			(unsigned long long)pkt_dev->count);
Linus Torvalds's avatar
Linus Torvalds committed
1112 1113 1114 1115
		return count;
	}
	if (!strcmp(name, "src_mac_count")) {
		len = num_arg(&user_buffer[i], 10, &value);
1116
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1117
			return len;
1118

Linus Torvalds's avatar
Linus Torvalds committed
1119 1120
		i += len;
		if (pkt_dev->src_mac_count != value) {
Luiz Capitulino's avatar
Luiz Capitulino committed
1121 1122 1123 1124 1125
			pkt_dev->src_mac_count = value;
			pkt_dev->cur_src_mac_offset = 0;
		}
		sprintf(pg_result, "OK: src_mac_count=%d",
			pkt_dev->src_mac_count);
Linus Torvalds's avatar
Linus Torvalds committed
1126 1127 1128 1129
		return count;
	}
	if (!strcmp(name, "dst_mac_count")) {
		len = num_arg(&user_buffer[i], 10, &value);
1130
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1131
			return len;
1132

Linus Torvalds's avatar
Linus Torvalds committed
1133 1134
		i += len;
		if (pkt_dev->dst_mac_count != value) {
Luiz Capitulino's avatar
Luiz Capitulino committed
1135 1136 1137 1138 1139
			pkt_dev->dst_mac_count = value;
			pkt_dev->cur_dst_mac_offset = 0;
		}
		sprintf(pg_result, "OK: dst_mac_count=%d",
			pkt_dev->dst_mac_count);
Linus Torvalds's avatar
Linus Torvalds committed
1140 1141
		return count;
	}
1142 1143 1144 1145 1146 1147
	if (!strcmp(name, "burst")) {
		len = num_arg(&user_buffer[i], 10, &value);
		if (len < 0)
			return len;

		i += len;
1148 1149 1150 1151
		if ((value > 1) &&
		    ((pkt_dev->xmit_mode == M_QUEUE_XMIT) ||
		     ((pkt_dev->xmit_mode == M_START_XMIT) &&
		     (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))))
1152
			return -ENOTSUPP;
1153 1154 1155 1156
		pkt_dev->burst = value < 1 ? 1 : value;
		sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
		return count;
	}
Robert Olsson's avatar
Robert Olsson committed
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	if (!strcmp(name, "node")) {
		len = num_arg(&user_buffer[i], 10, &value);
		if (len < 0)
			return len;

		i += len;

		if (node_possible(value)) {
			pkt_dev->node = value;
			sprintf(pg_result, "OK: node=%d", pkt_dev->node);
1167 1168 1169 1170
			if (pkt_dev->page) {
				put_page(pkt_dev->page);
				pkt_dev->page = NULL;
			}
Robert Olsson's avatar
Robert Olsson committed
1171 1172 1173 1174 1175
		}
		else
			sprintf(pg_result, "ERROR: node not possible");
		return count;
	}
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
	if (!strcmp(name, "xmit_mode")) {
		char f[32];

		memset(f, 0, 32);
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
		if (len < 0)
			return len;

		if (copy_from_user(f, &user_buffer[i], len))
			return -EFAULT;
		i += len;

		if (strcmp(f, "start_xmit") == 0) {
			pkt_dev->xmit_mode = M_START_XMIT;
		} else if (strcmp(f, "netif_receive") == 0) {
			/* clone_skb set earlier, not supported in this mode */
			if (pkt_dev->clone_skb > 0)
				return -ENOTSUPP;

			pkt_dev->xmit_mode = M_NETIF_RECEIVE;
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205

			/* make sure new packet is allocated every time
			 * pktgen_xmit() is called
			 */
			pkt_dev->last_ok = 1;

			/* override clone_skb if user passed default value
			 * at module loading time
			 */
			pkt_dev->clone_skb = 0;
1206 1207 1208
		} else if (strcmp(f, "queue_xmit") == 0) {
			pkt_dev->xmit_mode = M_QUEUE_XMIT;
			pkt_dev->last_ok = 1;
1209 1210 1211 1212 1213 1214 1215 1216 1217
		} else {
			sprintf(pg_result,
				"xmit_mode -:%s:- unknown\nAvailable modes: %s",
				f, "start_xmit, netif_receive\n");
			return count;
		}
		sprintf(pg_result, "OK: xmit_mode=%s", f);
		return count;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1218
	if (!strcmp(name, "flag")) {
1219
		__u32 flag;
Luiz Capitulino's avatar
Luiz Capitulino committed
1220
		char f[32];
1221 1222
		bool disable = false;

Luiz Capitulino's avatar
Luiz Capitulino committed
1223
		memset(f, 0, 32);
Linus Torvalds's avatar
Linus Torvalds committed
1224
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
1225
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1226
			return len;
1227

Linus Torvalds's avatar
Linus Torvalds committed
1228 1229 1230
		if (copy_from_user(f, &user_buffer[i], len))
			return -EFAULT;
		i += len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1231

1232
		flag = pktgen_read_flag(f, &disable);
Luiz Capitulino's avatar
Luiz Capitulino committed
1233

1234 1235 1236 1237 1238 1239
		if (flag) {
			if (disable)
				pkt_dev->flags &= ~flag;
			else
				pkt_dev->flags |= flag;
		} else {
Luiz Capitulino's avatar
Luiz Capitulino committed
1240 1241 1242
			sprintf(pg_result,
				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
				f,
Francesco Fondelli's avatar
Francesco Fondelli committed
1243
				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
1244 1245 1246
				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
				"MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
				"QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
1247
				"NO_TIMESTAMP, "
1248 1249 1250 1251
#ifdef CONFIG_XFRM
				"IPSEC, "
#endif
				"NODE_ALLOC\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
1252 1253
			return count;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1254 1255 1256 1257 1258
		sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
		return count;
	}
	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
1259
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1260
			return len;
Linus Torvalds's avatar
Linus Torvalds committed
1261

Luiz Capitulino's avatar
Luiz Capitulino committed
1262
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1263
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1264 1265 1266 1267 1268 1269 1270 1271
		buf[len] = 0;
		if (strcmp(buf, pkt_dev->dst_min) != 0) {
			memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
			strncpy(pkt_dev->dst_min, buf, len);
			pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
			pkt_dev->cur_daddr = pkt_dev->daddr_min;
		}
		if (debug)
Joe Perches's avatar
Joe Perches committed
1272
			pr_debug("dst_min set to: %s\n", pkt_dev->dst_min);
Luiz Capitulino's avatar
Luiz Capitulino committed
1273
		i += len;
Linus Torvalds's avatar
Linus Torvalds committed
1274 1275 1276 1277 1278
		sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
		return count;
	}
	if (!strcmp(name, "dst_max")) {
		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
1279
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1280
			return len;
1281

Linus Torvalds's avatar
Linus Torvalds committed
1282

Luiz Capitulino's avatar
Luiz Capitulino committed
1283
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1284 1285
			return -EFAULT;

Luiz Capitulino's avatar
Luiz Capitulino committed
1286 1287 1288 1289 1290 1291 1292 1293
		buf[len] = 0;
		if (strcmp(buf, pkt_dev->dst_max) != 0) {
			memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
			strncpy(pkt_dev->dst_max, buf, len);
			pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
			pkt_dev->cur_daddr = pkt_dev->daddr_max;
		}
		if (debug)
Joe Perches's avatar
Joe Perches committed
1294
			pr_debug("dst_max set to: %s\n", pkt_dev->dst_max);
Linus Torvalds's avatar
Linus Torvalds committed
1295 1296 1297 1298 1299 1300
		i += len;
		sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
		return count;
	}
	if (!strcmp(name, "dst6")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
Luiz Capitulino's avatar
Luiz Capitulino committed
1301 1302
		if (len < 0)
			return len;
Linus Torvalds's avatar
Linus Torvalds committed
1303 1304 1305

		pkt_dev->flags |= F_IPV6;

Luiz Capitulino's avatar
Luiz Capitulino committed
1306
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1307
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1308
		buf[len] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1309

1310
		in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL);
1311
		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
Linus Torvalds's avatar
Linus Torvalds committed
1312

1313
		pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr;
Linus Torvalds's avatar
Linus Torvalds committed
1314

Luiz Capitulino's avatar
Luiz Capitulino committed
1315
		if (debug)
Joe Perches's avatar
Joe Perches committed
1316
			pr_debug("dst6 set to: %s\n", buf);
Linus Torvalds's avatar
Linus Torvalds committed
1317

Luiz Capitulino's avatar
Luiz Capitulino committed
1318
		i += len;
Linus Torvalds's avatar
Linus Torvalds committed
1319 1320 1321 1322 1323
		sprintf(pg_result, "OK: dst6=%s", buf);
		return count;
	}
	if (!strcmp(name, "dst6_min")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
Luiz Capitulino's avatar
Luiz Capitulino committed
1324 1325
		if (len < 0)
			return len;
Linus Torvalds's avatar
Linus Torvalds committed
1326 1327 1328

		pkt_dev->flags |= F_IPV6;

Luiz Capitulino's avatar
Luiz Capitulino committed
1329
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1330
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1331
		buf[len] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1332

1333
		in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL);
1334
		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
Linus Torvalds's avatar
Linus Torvalds committed
1335

1336
		pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr;
Luiz Capitulino's avatar
Luiz Capitulino committed
1337
		if (debug)
Joe Perches's avatar
Joe Perches committed
1338
			pr_debug("dst6_min set to: %s\n", buf);
Linus Torvalds's avatar
Linus Torvalds committed
1339

Luiz Capitulino's avatar
Luiz Capitulino committed
1340
		i += len;
Linus Torvalds's avatar
Linus Torvalds committed
1341 1342 1343 1344 1345
		sprintf(pg_result, "OK: dst6_min=%s", buf);
		return count;
	}
	if (!strcmp(name, "dst6_max")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
Luiz Capitulino's avatar
Luiz Capitulino committed
1346 1347
		if (len < 0)
			return len;
Linus Torvalds's avatar
Linus Torvalds committed
1348 1349 1350

		pkt_dev->flags |= F_IPV6;

Luiz Capitulino's avatar
Luiz Capitulino committed
1351
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1352
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1353
		buf[len] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1354

1355
		in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL);
1356
		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
Linus Torvalds's avatar
Linus Torvalds committed
1357

Luiz Capitulino's avatar
Luiz Capitulino committed
1358
		if (debug)
Joe Perches's avatar
Joe Perches committed
1359
			pr_debug("dst6_max set to: %s\n", buf);
Linus Torvalds's avatar
Linus Torvalds committed
1360

Luiz Capitulino's avatar
Luiz Capitulino committed
1361
		i += len;
Linus Torvalds's avatar
Linus Torvalds committed
1362 1363 1364 1365 1366
		sprintf(pg_result, "OK: dst6_max=%s", buf);
		return count;
	}
	if (!strcmp(name, "src6")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
Luiz Capitulino's avatar
Luiz Capitulino committed
1367 1368
		if (len < 0)
			return len;
Linus Torvalds's avatar
Linus Torvalds committed
1369 1370 1371

		pkt_dev->flags |= F_IPV6;

Luiz Capitulino's avatar
Luiz Capitulino committed
1372
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1373
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1374
		buf[len] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1375

1376
		in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL);
1377
		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
Linus Torvalds's avatar
Linus Torvalds committed
1378

1379
		pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr;
Linus Torvalds's avatar
Linus Torvalds committed
1380

Luiz Capitulino's avatar
Luiz Capitulino committed
1381
		if (debug)
Joe Perches's avatar
Joe Perches committed
1382
			pr_debug("src6 set to: %s\n", buf);
Luiz Capitulino's avatar
Luiz Capitulino committed
1383 1384

		i += len;
Linus Torvalds's avatar
Linus Torvalds committed
1385 1386 1387 1388 1389
		sprintf(pg_result, "OK: src6=%s", buf);
		return count;
	}
	if (!strcmp(name, "src_min")) {
		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
1390
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1391
			return len;
1392

Luiz Capitulino's avatar
Luiz Capitulino committed
1393
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1394
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1395 1396 1397 1398 1399 1400 1401 1402
		buf[len] = 0;
		if (strcmp(buf, pkt_dev->src_min) != 0) {
			memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
			strncpy(pkt_dev->src_min, buf, len);
			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
			pkt_dev->cur_saddr = pkt_dev->saddr_min;
		}
		if (debug)
Joe Perches's avatar
Joe Perches committed
1403
			pr_debug("src_min set to: %s\n", pkt_dev->src_min);
Linus Torvalds's avatar
Linus Torvalds committed
1404 1405 1406 1407 1408 1409
		i += len;
		sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
		return count;
	}
	if (!strcmp(name, "src_max")) {
		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
1410
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1411
			return len;
1412

Luiz Capitulino's avatar
Luiz Capitulino committed
1413
		if (copy_from_user(buf, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1414
			return -EFAULT;
Luiz Capitulino's avatar
Luiz Capitulino committed
1415 1416 1417 1418 1419 1420 1421 1422
		buf[len] = 0;
		if (strcmp(buf, pkt_dev->src_max) != 0) {
			memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
			strncpy(pkt_dev->src_max, buf, len);
			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
			pkt_dev->cur_saddr = pkt_dev->saddr_max;
		}
		if (debug)
Joe Perches's avatar
Joe Perches committed
1423
			pr_debug("src_max set to: %s\n", pkt_dev->src_max);
Linus Torvalds's avatar
Linus Torvalds committed
1424 1425 1426 1427 1428 1429
		i += len;
		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
		return count;
	}
	if (!strcmp(name, "dst_mac")) {
		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
1430
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1431
			return len;
1432

Linus Torvalds's avatar
Linus Torvalds committed
1433
		memset(valstr, 0, sizeof(valstr));
Luiz Capitulino's avatar
Luiz Capitulino committed
1434
		if (copy_from_user(valstr, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1435 1436
			return -EFAULT;

1437 1438
		if (!mac_pton(valstr, pkt_dev->dst_mac))
			return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1439
		/* Set up Dest MAC */
Joe Perches's avatar
Joe Perches committed
1440
		ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac);
Luiz Capitulino's avatar
Luiz Capitulino committed
1441

1442
		sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
Linus Torvalds's avatar
Linus Torvalds committed
1443 1444 1445 1446
		return count;
	}
	if (!strcmp(name, "src_mac")) {
		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
1447
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1448
			return len;
1449

Linus Torvalds's avatar
Linus Torvalds committed
1450
		memset(valstr, 0, sizeof(valstr));
Luiz Capitulino's avatar
Luiz Capitulino committed
1451
		if (copy_from_user(valstr, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1452 1453
			return -EFAULT;

1454 1455
		if (!mac_pton(valstr, pkt_dev->src_mac))
			return -EINVAL;
Adit Ranadive's avatar
Adit Ranadive committed
1456
		/* Set up Src MAC */
Joe Perches's avatar
Joe Perches committed
1457
		ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac);
Adit Ranadive's avatar
Adit Ranadive committed
1458

1459
		sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
Linus Torvalds's avatar
Linus Torvalds committed
1460 1461 1462
		return count;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
1463 1464 1465 1466 1467
	if (!strcmp(name, "clear_counters")) {
		pktgen_clear_counters(pkt_dev);
		sprintf(pg_result, "OK: Clearing counters.\n");
		return count;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1468 1469 1470

	if (!strcmp(name, "flows")) {
		len = num_arg(&user_buffer[i], 10, &value);
1471
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1472
			return len;
1473

Linus Torvalds's avatar
Linus Torvalds committed
1474 1475 1476 1477 1478 1479 1480 1481
		i += len;
		if (value > MAX_CFLOWS)
			value = MAX_CFLOWS;

		pkt_dev->cflows = value;
		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
		return count;
	}
1482
#ifdef CONFIG_XFRM
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
	if (!strcmp(name, "spi")) {
		len = num_arg(&user_buffer[i], 10, &value);
		if (len < 0)
			return len;

		i += len;
		pkt_dev->spi = value;
		sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
		return count;
	}
1493
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1494 1495
	if (!strcmp(name, "flowlen")) {
		len = num_arg(&user_buffer[i], 10, &value);
1496
		if (len < 0)
Luiz Capitulino's avatar
Luiz Capitulino committed
1497
			return len;
1498

Linus Torvalds's avatar
Linus Torvalds committed
1499 1500 1501 1502 1503
		i += len;
		pkt_dev->lflow = value;
		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
		return count;
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
1504

1505 1506
	if (!strcmp(name, "queue_map_min")) {
		len = num_arg(&user_buffer[i], 5, &value);
1507
		if (len < 0)
1508
			return len;
1509

1510 1511 1512 1513 1514 1515 1516 1517
		i += len;
		pkt_dev->queue_map_min = value;
		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
		return count;
	}

	if (!strcmp(name, "queue_map_max")) {
		len = num_arg(&user_buffer[i], 5, &value);
1518
		if (len < 0)
1519
			return len;
1520

1521 1522 1523 1524 1525 1526
		i += len;
		pkt_dev->queue_map_max = value;
		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
		return count;
	}

1527
	if (!strcmp(name, "mpls")) {
1528
		unsigned int n, cnt;
1529

1530
		len = get_labels(&user_buffer[i], pkt_dev);
1531 1532
		if (len < 0)
			return len;
1533
		i += len;
1534
		cnt = sprintf(pg_result, "OK: mpls=");
1535
		for (n = 0; n < pkt_dev->nr_labels; n++)
1536 1537 1538
			cnt += sprintf(pg_result + cnt,
				       "%08x%s", ntohl(pkt_dev->labels[n]),
				       n == pkt_dev->nr_labels-1 ? "" : ",");
Francesco Fondelli's avatar
Francesco Fondelli committed
1539 1540 1541 1542 1543 1544

		if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
			pkt_dev->svlan_id = 0xffff;

			if (debug)
Joe Perches's avatar
Joe Perches committed
1545
				pr_debug("VLAN/SVLAN auto turned off\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1546 1547 1548 1549 1550 1551
		}
		return count;
	}

	if (!strcmp(name, "vlan_id")) {
		len = num_arg(&user_buffer[i], 4, &value);
1552
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1553
			return len;
1554

Francesco Fondelli's avatar
Francesco Fondelli committed
1555 1556 1557 1558 1559
		i += len;
		if (value <= 4095) {
			pkt_dev->vlan_id = value;  /* turn on VLAN */

			if (debug)
Joe Perches's avatar
Joe Perches committed
1560
				pr_debug("VLAN turned on\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1561 1562

			if (debug && pkt_dev->nr_labels)
Joe Perches's avatar
Joe Perches committed
1563
				pr_debug("MPLS auto turned off\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1564 1565 1566 1567 1568 1569 1570 1571

			pkt_dev->nr_labels = 0;    /* turn off MPLS */
			sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
		} else {
			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
			pkt_dev->svlan_id = 0xffff;

			if (debug)
Joe Perches's avatar
Joe Perches committed
1572
				pr_debug("VLAN/SVLAN turned off\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1573 1574 1575 1576 1577 1578
		}
		return count;
	}

	if (!strcmp(name, "vlan_p")) {
		len = num_arg(&user_buffer[i], 1, &value);
1579
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1580
			return len;
1581

Francesco Fondelli's avatar
Francesco Fondelli committed
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
		i += len;
		if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
			pkt_dev->vlan_p = value;
			sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
		} else {
			sprintf(pg_result, "ERROR: vlan_p must be 0-7");
		}
		return count;
	}

	if (!strcmp(name, "vlan_cfi")) {
		len = num_arg(&user_buffer[i], 1, &value);
1594
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1595
			return len;
1596

Francesco Fondelli's avatar
Francesco Fondelli committed
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
		i += len;
		if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
			pkt_dev->vlan_cfi = value;
			sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
		} else {
			sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
		}
		return count;
	}

	if (!strcmp(name, "svlan_id")) {
		len = num_arg(&user_buffer[i], 4, &value);
1609
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1610
			return len;
1611

Francesco Fondelli's avatar
Francesco Fondelli committed
1612 1613 1614 1615 1616
		i += len;
		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
			pkt_dev->svlan_id = value;  /* turn on SVLAN */

			if (debug)
Joe Perches's avatar
Joe Perches committed
1617
				pr_debug("SVLAN turned on\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1618 1619

			if (debug && pkt_dev->nr_labels)
Joe Perches's avatar
Joe Perches committed
1620
				pr_debug("MPLS auto turned off\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1621 1622 1623 1624 1625 1626 1627 1628

			pkt_dev->nr_labels = 0;    /* turn off MPLS */
			sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
		} else {
			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
			pkt_dev->svlan_id = 0xffff;

			if (debug)
Joe Perches's avatar
Joe Perches committed
1629
				pr_debug("VLAN/SVLAN turned off\n");
Francesco Fondelli's avatar
Francesco Fondelli committed
1630 1631 1632 1633 1634 1635
		}
		return count;
	}

	if (!strcmp(name, "svlan_p")) {
		len = num_arg(&user_buffer[i], 1, &value);
1636
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1637
			return len;
1638

Francesco Fondelli's avatar
Francesco Fondelli committed
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
		i += len;
		if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
			pkt_dev->svlan_p = value;
			sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
		} else {
			sprintf(pg_result, "ERROR: svlan_p must be 0-7");
		}
		return count;
	}

	if (!strcmp(name, "svlan_cfi")) {
		len = num_arg(&user_buffer[i], 1, &value);
1651
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1652
			return len;
1653

Francesco Fondelli's avatar
Francesco Fondelli committed
1654 1655 1656 1657 1658 1659 1660
		i += len;
		if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
			pkt_dev->svlan_cfi = value;
			sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
		} else {
			sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
		}
1661 1662 1663
		return count;
	}

Francesco Fondelli's avatar
Francesco Fondelli committed
1664 1665 1666
	if (!strcmp(name, "tos")) {
		__u32 tmp_value = 0;
		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
1667
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1668
			return len;
1669

Francesco Fondelli's avatar
Francesco Fondelli committed
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
		i += len;
		if (len == 2) {
			pkt_dev->tos = tmp_value;
			sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
		} else {
			sprintf(pg_result, "ERROR: tos must be 00-ff");
		}
		return count;
	}

	if (!strcmp(name, "traffic_class")) {
		__u32 tmp_value = 0;
		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
1683
		if (len < 0)
Francesco Fondelli's avatar
Francesco Fondelli committed
1684
			return len;
1685

Francesco Fondelli's avatar
Francesco Fondelli committed
1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
		i += len;
		if (len == 2) {
			pkt_dev->traffic_class = tmp_value;
			sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
		} else {
			sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
		}
		return count;
	}

1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
	if (!strcmp(name, "skb_priority")) {
		len = num_arg(&user_buffer[i], 9, &value);
		if (len < 0)
			return len;

		i += len;
		pkt_dev->skb_priority = value;
		sprintf(pg_result, "OK: skb_priority=%i",
			pkt_dev->skb_priority);
		return count;
	}

Linus Torvalds's avatar
Linus Torvalds committed
1708 1709 1710 1711
	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
	return -EINVAL;
}

1712
static int pktgen_if_open(struct inode *inode, struct file *file)
Linus Torvalds's avatar
Linus Torvalds committed
1713
{
1714
	return single_open(file, pktgen_if_show, PDE_DATA(inode));
1715
}
Linus Torvalds's avatar
Linus Torvalds committed
1716

1717
static const struct file_operations pktgen_if_fops = {
Luiz Capitulino's avatar
Luiz Capitulino committed
1718 1719 1720 1721 1722
	.open    = pktgen_if_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pktgen_if_write,
	.release = single_release,
1723
};
Linus Torvalds's avatar
Linus Torvalds committed
1724

1725 1726
static int pktgen_thread_show(struct seq_file *seq, void *v)
{
Luiz Capitulino's avatar
Luiz Capitulino committed
1727
	struct pktgen_thread *t = seq->private;
Stephen Hemminger's avatar
Stephen Hemminger committed
1728
	const struct pktgen_dev *pkt_dev;
1729 1730

	BUG_ON(!t);
Linus Torvalds's avatar
Linus Torvalds committed
1731

1732
	seq_puts(seq, "Running: ");
Linus Torvalds's avatar
Linus Torvalds committed
1733

1734 1735
	rcu_read_lock();
	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
Luiz Capitulino's avatar
Luiz Capitulino committed
1736
		if (pkt_dev->running)
1737
			seq_printf(seq, "%s ", pkt_dev->odevname);
Linus Torvalds's avatar
Linus Torvalds committed
1738

1739
	seq_puts(seq, "\nStopped: ");
Luiz Capitulino's avatar
Luiz Capitulino committed
1740

1741
	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
Luiz Capitulino's avatar
Luiz Capitulino committed
1742
		if (!pkt_dev->running)
1743
			seq_printf(seq, "%s ", pkt_dev->odevname);
Linus Torvalds's avatar
Linus Torvalds committed
1744 1745

	if (t->result[0])
1746
		seq_printf(seq, "\nResult: %s\n", t->result);
Linus Torvalds's avatar
Linus Torvalds committed
1747
	else
1748
		seq_puts(seq, "\nResult: NA\n");
Linus Torvalds's avatar
Linus Torvalds committed
1749

1750
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
1751

1752
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1753 1754
}

1755
static ssize_t pktgen_thread_write(struct file *file,
Luiz Capitulino's avatar
Luiz Capitulino committed
1756 1757
				   const char __user * user_buffer,
				   size_t count, loff_t * offset)
Linus Torvalds's avatar
Linus Torvalds committed
1758
{
1759
	struct seq_file *seq = file->private_data;
Luiz Capitulino's avatar
Luiz Capitulino committed
1760
	struct pktgen_thread *t = seq->private;
1761
	int i, max, len, ret;
Linus Torvalds's avatar
Linus Torvalds committed
1762
	char name[40];
Luiz Capitulino's avatar
Luiz Capitulino committed
1763
	char *pg_result;
1764

Linus Torvalds's avatar
Linus Torvalds committed
1765
	if (count < 1) {
Luiz Capitulino's avatar
Luiz Capitulino committed
1766
		//      sprintf(pg_result, "Wrong command format");
Linus Torvalds's avatar
Linus Torvalds committed
1767 1768
		return -EINVAL;
	}
1769

1770 1771
	max = count;
	len = count_trail_chars(user_buffer, max);
Luiz Capitulino's avatar
Luiz Capitulino committed
1772
	if (len < 0)
1773 1774
		return len;

1775
	i = len;
1776

Linus Torvalds's avatar
Linus Torvalds committed
1777 1778 1779
	/* Read variable name */

	len = strn_len(&user_buffer[i], sizeof(name) - 1);
Luiz Capitulino's avatar
Luiz Capitulino committed
1780
	if (len < 0)
1781
		return len;
Luiz Capitulino's avatar
Luiz Capitulino committed
1782

Linus Torvalds's avatar
Linus Torvalds committed
1783 1784 1785 1786
	memset(name, 0, sizeof(name));
	if (copy_from_user(name, &user_buffer[i], len))
		return -EFAULT;
	i += len;
1787

Luiz Capitulino's avatar
Luiz Capitulino committed
1788
	max = count - i;
Linus Torvalds's avatar
Linus Torvalds committed
1789
	len = count_trail_chars(&user_buffer[i], max);
Luiz Capitulino's avatar
Luiz Capitulino committed
1790
	if (len < 0)
1791 1792
		return len;

Linus Torvalds's avatar
Linus Torvalds committed
1793 1794
	i += len;

1795
	if (debug)
Joe Perches's avatar
Joe Perches committed
1796
		pr_debug("t=%s, count=%lu\n", name, (unsigned long)count);
Linus Torvalds's avatar
Linus Torvalds committed
1797

Luiz Capitulino's avatar
Luiz Capitulino committed
1798
	if (!t) {
1799
		pr_err("ERROR: No thread\n");
Linus Torvalds's avatar
Linus Torvalds committed
1800 1801 1802 1803 1804 1805
		ret = -EINVAL;
		goto out;
	}

	pg_result = &(t->result[0]);

Luiz Capitulino's avatar
Luiz Capitulino committed
1806 1807 1808
	if (!strcmp(name, "add_device")) {
		char f[32];
		memset(f, 0, 32);
Linus Torvalds's avatar
Linus Torvalds committed
1809
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
Luiz Capitulino's avatar
Luiz Capitulino committed
1810 1811
		if (len < 0) {
			ret = len;
Linus Torvalds's avatar
Linus Torvalds committed
1812 1813
			goto out;
		}
Luiz Capitulino's avatar
Luiz Capitulino committed
1814
		if (copy_from_user(f, &user_buffer[i], len))
Linus Torvalds's avatar
Linus Torvalds committed
1815 1816
			return -EFAULT;
		i += len;
1817
		mutex_lock(&pktgen_thread_lock);
1818
		ret = pktgen_add_device(t, f);
1819
		mutex_unlock(&pktgen_thread_lock);
1820 1821 1822 1823 1824
		if (!ret) {
			ret = count;
			sprintf(pg_result, "OK: add_device=%s", f);
		} else
			sprintf(pg_result, "ERROR: can not add device %s", f);
Linus Torvalds's avatar
Linus Torvalds committed
1825 1826 1827
		goto out;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
1828
	if (!strcmp(name, "rem_device_all")) {
1829
		mutex_lock(&pktgen_thread_lock);
1830
		t->control |= T_REMDEVALL;
1831
		mutex_unlock(&pktgen_thread_lock);
Luiz Capitulino's avatar
Luiz Capitulino committed
1832
		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
Linus Torvalds's avatar
Linus Torvalds committed
1833
		ret = count;
Luiz Capitulino's avatar
Luiz Capitulino committed
1834
		sprintf(pg_result, "OK: rem_device_all");
Linus Torvalds's avatar
Linus Torvalds committed
1835 1836 1837
		goto out;
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
1838
	if (!strcmp(name, "max_before_softirq")) {
1839
		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
Luiz Capitulino's avatar
Luiz Capitulino committed
1840
		ret = count;
Linus Torvalds's avatar
Linus Torvalds committed
1841 1842 1843 1844
		goto out;
	}

	ret = -EINVAL;
Luiz Capitulino's avatar
Luiz Capitulino committed
1845
out:
Linus Torvalds's avatar
Linus Torvalds committed
1846 1847 1848
	return ret;
}

1849
static int pktgen_thread_open(struct inode *inode, struct file *file)
Linus Torvalds's avatar
Linus Torvalds committed
1850
{
1851
	return single_open(file, pktgen_thread_show, PDE_DATA(inode));
Linus Torvalds's avatar
Linus Torvalds committed
1852 1853
}

1854
static const struct file_operations pktgen_thread_fops = {
Luiz Capitulino's avatar
Luiz Capitulino committed
1855 1856 1857 1858 1859
	.open    = pktgen_thread_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pktgen_thread_write,
	.release = single_release,
1860
};
Linus Torvalds's avatar
Linus Torvalds committed
1861 1862

/* Think find or remove for NN */
Cong Wang's avatar
Cong Wang committed
1863 1864
static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn,
					      const char *ifname, int remove)
Linus Torvalds's avatar
Linus Torvalds committed
1865 1866 1867
{
	struct pktgen_thread *t;
	struct pktgen_dev *pkt_dev = NULL;
1868
	bool exact = (remove == FIND);
Linus Torvalds's avatar
Linus Torvalds committed
1869

Cong Wang's avatar
Cong Wang committed
1870
	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
1871
		pkt_dev = pktgen_find_dev(t, ifname, exact);
Linus Torvalds's avatar
Linus Torvalds committed
1872
		if (pkt_dev) {
Luiz Capitulino's avatar
Luiz Capitulino committed
1873 1874 1875 1876
			if (remove) {
				pkt_dev->removal_mark = 1;
				t->control |= T_REMDEV;
			}
Linus Torvalds's avatar
Linus Torvalds committed
1877 1878 1879
			break;
		}
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
1880
	return pkt_dev;
Linus Torvalds's avatar
Linus Torvalds committed
1881 1882
}

1883 1884 1885
/*
 * mark a device for removal
 */
Cong Wang's avatar
Cong Wang committed
1886
static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname)
Linus Torvalds's avatar
Linus Torvalds committed
1887 1888
{
	struct pktgen_dev *pkt_dev = NULL;
1889 1890 1891
	const int max_tries = 10, msec_per_try = 125;
	int i = 0;

1892
	mutex_lock(&pktgen_thread_lock);
1893
	pr_debug("%s: marking %s for removal\n", __func__, ifname);
1894

Luiz Capitulino's avatar
Luiz Capitulino committed
1895
	while (1) {
1896

Cong Wang's avatar
Cong Wang committed
1897
		pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE);
Luiz Capitulino's avatar
Luiz Capitulino committed
1898 1899
		if (pkt_dev == NULL)
			break;	/* success */
1900

1901
		mutex_unlock(&pktgen_thread_lock);
1902 1903
		pr_debug("%s: waiting for %s to disappear....\n",
			 __func__, ifname);
1904
		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
1905
		mutex_lock(&pktgen_thread_lock);
1906 1907

		if (++i >= max_tries) {
1908 1909
			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
			       __func__, msec_per_try * i, ifname);
1910 1911 1912 1913 1914
			break;
		}

	}

1915
	mutex_unlock(&pktgen_thread_lock);
1916
}
1917

Cong Wang's avatar
Cong Wang committed
1918
static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev)
1919 1920 1921
{
	struct pktgen_thread *t;

1922 1923
	mutex_lock(&pktgen_thread_lock);

Cong Wang's avatar
Cong Wang committed
1924
	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
1925 1926
		struct pktgen_dev *pkt_dev;

1927 1928
		if_lock(t);
		list_for_each_entry(pkt_dev, &t->if_list, list) {
1929 1930 1931
			if (pkt_dev->odev != dev)
				continue;

1932
			proc_remove(pkt_dev->entry);
1933

1934
			pkt_dev->entry = proc_create_data(dev->name, 0600,
Cong Wang's avatar
Cong Wang committed
1935
							  pn->proc_dir,
1936 1937
							  &pktgen_if_fops,
							  pkt_dev);
1938
			if (!pkt_dev->entry)
1939 1940
				pr_err("can't move proc entry for '%s'\n",
				       dev->name);
1941 1942
			break;
		}
1943
		if_unlock(t);
1944
	}
1945
	mutex_unlock(&pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
1946 1947
}

Luiz Capitulino's avatar
Luiz Capitulino committed
1948 1949
static int pktgen_device_event(struct notifier_block *unused,
			       unsigned long event, void *ptr)
Linus Torvalds's avatar
Linus Torvalds committed
1950
{
1951
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Cong Wang's avatar
Cong Wang committed
1952
	struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id);
Linus Torvalds's avatar
Linus Torvalds committed
1953

Cong Wang's avatar
Cong Wang committed
1954
	if (pn->pktgen_exiting)
1955 1956
		return NOTIFY_DONE;

Linus Torvalds's avatar
Linus Torvalds committed
1957 1958 1959 1960 1961
	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
1962
	case NETDEV_CHANGENAME:
Cong Wang's avatar
Cong Wang committed
1963
		pktgen_change_name(pn, dev);
Linus Torvalds's avatar
Linus Torvalds committed
1964
		break;
Luiz Capitulino's avatar
Luiz Capitulino committed
1965

Linus Torvalds's avatar
Linus Torvalds committed
1966
	case NETDEV_UNREGISTER:
Cong Wang's avatar
Cong Wang committed
1967
		pktgen_mark_device(pn, dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
1968
		break;
1969
	}
Linus Torvalds's avatar
Linus Torvalds committed
1970 1971 1972 1973

	return NOTIFY_DONE;
}

Cong Wang's avatar
Cong Wang committed
1974 1975
static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn,
						 struct pktgen_dev *pkt_dev,
1976
						 const char *ifname)
Robert Olsson's avatar
Robert Olsson committed
1977 1978
{
	char b[IFNAMSIZ+5];
1979
	int i;
Robert Olsson's avatar
Robert Olsson committed
1980

1981 1982
	for (i = 0; ifname[i] != '@'; i++) {
		if (i == IFNAMSIZ)
Robert Olsson's avatar
Robert Olsson committed
1983 1984 1985 1986 1987 1988
			break;

		b[i] = ifname[i];
	}
	b[i] = 0;

Cong Wang's avatar
Cong Wang committed
1989
	return dev_get_by_name(pn->net, b);
Robert Olsson's avatar
Robert Olsson committed
1990 1991 1992
}


Linus Torvalds's avatar
Linus Torvalds committed
1993 1994
/* Associate pktgen_dev with a device. */

Cong Wang's avatar
Cong Wang committed
1995 1996
static int pktgen_setup_dev(const struct pktgen_net *pn,
			    struct pktgen_dev *pkt_dev, const char *ifname)
Luiz Capitulino's avatar
Luiz Capitulino committed
1997
{
Linus Torvalds's avatar
Linus Torvalds committed
1998
	struct net_device *odev;
1999
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
2000 2001 2002 2003

	/* Clean old setups */
	if (pkt_dev->odev) {
		dev_put(pkt_dev->odev);
Luiz Capitulino's avatar
Luiz Capitulino committed
2004 2005
		pkt_dev->odev = NULL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
2006

Cong Wang's avatar
Cong Wang committed
2007
	odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname);
Linus Torvalds's avatar
Linus Torvalds committed
2008
	if (!odev) {
2009
		pr_err("no such netdevice: \"%s\"\n", ifname);
2010
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
2011
	}
2012

Linus Torvalds's avatar
Linus Torvalds committed
2013
	if (odev->type != ARPHRD_ETHER) {
2014
		pr_err("not an ethernet device: \"%s\"\n", ifname);
2015 2016
		err = -EINVAL;
	} else if (!netif_running(odev)) {
2017
		pr_err("device is down: \"%s\"\n", ifname);
2018 2019 2020 2021
		err = -ENETDOWN;
	} else {
		pkt_dev->odev = odev;
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2022 2023 2024
	}

	dev_put(odev);
2025
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
2026 2027 2028 2029 2030 2031 2032
}

/* Read pkt_dev from the interface and set up internal pktgen_dev
 * structure to have the right information to create/send packets
 */
static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
{
2033 2034
	int ntxq;

Luiz Capitulino's avatar
Luiz Capitulino committed
2035
	if (!pkt_dev->odev) {
2036
		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
2037 2038 2039 2040 2041
		sprintf(pkt_dev->result,
			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
		return;
	}

2042 2043
	/* make sure that we don't pick a non-existing transmit queue */
	ntxq = pkt_dev->odev->real_num_tx_queues;
2044

2045
	if (ntxq <= pkt_dev->queue_map_min) {
2046 2047 2048
		pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
			pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
			pkt_dev->odevname);
2049
		pkt_dev->queue_map_min = (ntxq ?: 1) - 1;
2050
	}
2051
	if (pkt_dev->queue_map_max >= ntxq) {
2052 2053 2054
		pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
			pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
			pkt_dev->odevname);
2055
		pkt_dev->queue_map_max = (ntxq ?: 1) - 1;
2056 2057
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
2058
	/* Default to the interface's mac if not explicitly set. */
Linus Torvalds's avatar
Linus Torvalds committed
2059

2060
	if (is_zero_ether_addr(pkt_dev->src_mac))
Joe Perches's avatar
Joe Perches committed
2061
		ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr);
Linus Torvalds's avatar
Linus Torvalds committed
2062

Luiz Capitulino's avatar
Luiz Capitulino committed
2063
	/* Set up Dest MAC */
Joe Perches's avatar
Joe Perches committed
2064
	ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac);
Linus Torvalds's avatar
Linus Torvalds committed
2065

Luiz Capitulino's avatar
Luiz Capitulino committed
2066
	if (pkt_dev->flags & F_IPV6) {
2067 2068 2069
		int i, set = 0, err = 1;
		struct inet6_dev *idev;

2070 2071 2072 2073 2074 2075 2076
		if (pkt_dev->min_pkt_size == 0) {
			pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr)
						+ sizeof(struct udphdr)
						+ sizeof(struct pktgen_hdr)
						+ pkt_dev->pkt_overhead;
		}

2077
		for (i = 0; i < sizeof(struct in6_addr); i++)
Luiz Capitulino's avatar
Luiz Capitulino committed
2078
			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
Linus Torvalds's avatar
Linus Torvalds committed
2079 2080 2081 2082
				set = 1;
				break;
			}

Luiz Capitulino's avatar
Luiz Capitulino committed
2083 2084
		if (!set) {

Linus Torvalds's avatar
Linus Torvalds committed
2085 2086 2087 2088 2089 2090
			/*
			 * Use linklevel address if unconfigured.
			 *
			 * use ipv6_get_lladdr if/when it's get exported
			 */

2091
			rcu_read_lock();
2092 2093
			idev = __in6_dev_get(pkt_dev->odev);
			if (idev) {
Linus Torvalds's avatar
Linus Torvalds committed
2094 2095 2096
				struct inet6_ifaddr *ifp;

				read_lock_bh(&idev->lock);
2097 2098
				list_for_each_entry(ifp, &idev->addr_list, if_list) {
					if ((ifp->scope & IFA_LINK) &&
2099
					    !(ifp->flags & IFA_F_TENTATIVE)) {
2100
						pkt_dev->cur_in6_saddr = ifp->addr;
Linus Torvalds's avatar
Linus Torvalds committed
2101 2102 2103 2104 2105 2106
						err = 0;
						break;
					}
				}
				read_unlock_bh(&idev->lock);
			}
2107
			rcu_read_unlock();
Luiz Capitulino's avatar
Luiz Capitulino committed
2108
			if (err)
2109
				pr_err("ERROR: IPv6 link address not available\n");
Linus Torvalds's avatar
Linus Torvalds committed
2110
		}
Luiz Capitulino's avatar
Luiz Capitulino committed
2111
	} else {
2112 2113 2114 2115 2116 2117 2118
		if (pkt_dev->min_pkt_size == 0) {
			pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr)
						+ sizeof(struct udphdr)
						+ sizeof(struct pktgen_hdr)
						+ pkt_dev->pkt_overhead;
		}

Linus Torvalds's avatar
Linus Torvalds committed
2119 2120 2121
		pkt_dev->saddr_min = 0;
		pkt_dev->saddr_max = 0;
		if (strlen(pkt_dev->src_min) == 0) {
Luiz Capitulino's avatar
Luiz Capitulino committed
2122 2123

			struct in_device *in_dev;
Linus Torvalds's avatar
Linus Torvalds committed
2124 2125

			rcu_read_lock();
2126
			in_dev = __in_dev_get_rcu(pkt_dev->odev);
Linus Torvalds's avatar
Linus Torvalds committed
2127 2128
			if (in_dev) {
				if (in_dev->ifa_list) {
Luiz Capitulino's avatar
Luiz Capitulino committed
2129 2130
					pkt_dev->saddr_min =
					    in_dev->ifa_list->ifa_address;
Linus Torvalds's avatar
Linus Torvalds committed
2131 2132 2133 2134
					pkt_dev->saddr_max = pkt_dev->saddr_min;
				}
			}
			rcu_read_unlock();
Luiz Capitulino's avatar
Luiz Capitulino committed
2135
		} else {
Linus Torvalds's avatar
Linus Torvalds committed
2136 2137 2138 2139 2140 2141 2142
			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
		}

		pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
		pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
2143
	/* Initialize current values. */
2144 2145 2146 2147
	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
	if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size)
		pkt_dev->max_pkt_size = pkt_dev->min_pkt_size;

Luiz Capitulino's avatar
Luiz Capitulino committed
2148 2149 2150 2151 2152 2153
	pkt_dev->cur_dst_mac_offset = 0;
	pkt_dev->cur_src_mac_offset = 0;
	pkt_dev->cur_saddr = pkt_dev->saddr_min;
	pkt_dev->cur_daddr = pkt_dev->daddr_min;
	pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
	pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
Linus Torvalds's avatar
Linus Torvalds committed
2154 2155 2156
	pkt_dev->nflows = 0;
}

2157 2158 2159

static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
{
2160
	ktime_t start_time, end_time;
Eric Dumazet's avatar
Eric Dumazet committed
2161
	s64 remaining;
2162 2163 2164 2165 2166
	struct hrtimer_sleeper t;

	hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	hrtimer_set_expires(&t.timer, spin_until);

2167
	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
2168 2169
	if (remaining <= 0)
		goto out;
2170

2171
	start_time = ktime_get();
Eric Dumazet's avatar
Eric Dumazet committed
2172 2173 2174
	if (remaining < 100000) {
		/* for small delays (<100us), just loop until limit is reached */
		do {
2175 2176
			end_time = ktime_get();
		} while (ktime_compare(end_time, spin_until) < 0);
Eric Dumazet's avatar
Eric Dumazet committed
2177
	} else {
2178 2179 2180 2181 2182 2183 2184
		/* see do_nanosleep */
		hrtimer_init_sleeper(&t, current);
		do {
			set_current_state(TASK_INTERRUPTIBLE);
			hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);

			if (likely(t.task))
Linus Torvalds's avatar
Linus Torvalds committed
2185 2186
				schedule();

2187 2188 2189
			hrtimer_cancel(&t.timer);
		} while (t.task && pkt_dev->running && !signal_pending(current));
		__set_current_state(TASK_RUNNING);
2190
		end_time = ktime_get();
Linus Torvalds's avatar
Linus Torvalds committed
2191
	}
2192 2193

	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
2194
out:
2195
	pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
2196
	destroy_hrtimer_on_stack(&t.timer);
Linus Torvalds's avatar
Linus Torvalds committed
2197 2198
}

2199 2200
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
{
Paolo Abeni's avatar
Paolo Abeni committed
2201
	pkt_dev->pkt_overhead = 0;
2202 2203 2204 2205 2206
	pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
	pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
	pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
}

Stephen Hemminger's avatar
Stephen Hemminger committed
2207
static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
2208
{
Stephen Hemminger's avatar
Stephen Hemminger committed
2209
	return !!(pkt_dev->flows[flow].flags & F_INIT);
2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
}

static inline int f_pick(struct pktgen_dev *pkt_dev)
{
	int flow = pkt_dev->curfl;

	if (pkt_dev->flags & F_FLOW_SEQ) {
		if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
			/* reset time */
			pkt_dev->flows[flow].count = 0;
Robert Olsson's avatar
Robert Olsson committed
2220
			pkt_dev->flows[flow].flags = 0;
2221 2222 2223 2224 2225
			pkt_dev->curfl += 1;
			if (pkt_dev->curfl >= pkt_dev->cflows)
				pkt_dev->curfl = 0; /*reset */
		}
	} else {
2226
		flow = prandom_u32() % pkt_dev->cflows;
Robert Olsson's avatar
Robert Olsson committed
2227
		pkt_dev->curfl = flow;
2228

Robert Olsson's avatar
Robert Olsson committed
2229
		if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
2230
			pkt_dev->flows[flow].count = 0;
Robert Olsson's avatar
Robert Olsson committed
2231 2232
			pkt_dev->flows[flow].flags = 0;
		}
2233 2234 2235 2236 2237
	}

	return pkt_dev->curfl;
}

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2238 2239 2240 2241 2242

#ifdef CONFIG_XFRM
/* If there was already an IPSEC SA, we keep it as is, else
 * we go look for it ...
*/
2243
#define DUMMY_MARK 0
2244
static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2245 2246
{
	struct xfrm_state *x = pkt_dev->flows[flow].x;
Cong Wang's avatar
Cong Wang committed
2247
	struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2248
	if (!x) {
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263

		if (pkt_dev->spi) {
			/* We need as quick as possible to find the right SA
			 * Searching with minimum criteria to archieve this.
			 */
			x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
		} else {
			/* slow path: we dont already have xfrm_state */
			x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
						(xfrm_address_t *)&pkt_dev->cur_daddr,
						(xfrm_address_t *)&pkt_dev->cur_saddr,
						AF_INET,
						pkt_dev->ipsmode,
						pkt_dev->ipsproto, 0);
		}
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2264 2265 2266
		if (x) {
			pkt_dev->flows[flow].x = x;
			set_pkt_overhead(pkt_dev);
2267
			pkt_dev->pkt_overhead += x->props.header_len;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2268 2269 2270 2271 2272
		}

	}
}
#endif
2273 2274
static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
{
Robert Olsson's avatar
Robert Olsson committed
2275 2276 2277 2278

	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
		pkt_dev->cur_queue_map = smp_processor_id();

2279
	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
2280 2281
		__u16 t;
		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
2282
			t = prandom_u32() %
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
				(pkt_dev->queue_map_max -
				 pkt_dev->queue_map_min + 1)
				+ pkt_dev->queue_map_min;
		} else {
			t = pkt_dev->cur_queue_map + 1;
			if (t > pkt_dev->queue_map_max)
				t = pkt_dev->queue_map_min;
		}
		pkt_dev->cur_queue_map = t;
	}
2293
	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
2294 2295
}

Linus Torvalds's avatar
Linus Torvalds committed
2296 2297 2298
/* Increment/randomize headers according to flags and current values
 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
 */
Luiz Capitulino's avatar
Luiz Capitulino committed
2299 2300 2301 2302 2303
static void mod_cur_headers(struct pktgen_dev *pkt_dev)
{
	__u32 imn;
	__u32 imx;
	int flow = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2304

2305 2306
	if (pkt_dev->cflows)
		flow = f_pick(pkt_dev);
Linus Torvalds's avatar
Linus Torvalds committed
2307 2308

	/*  Deal with source MAC */
Luiz Capitulino's avatar
Luiz Capitulino committed
2309 2310 2311 2312 2313
	if (pkt_dev->src_mac_count > 1) {
		__u32 mc;
		__u32 tmp;

		if (pkt_dev->flags & F_MACSRC_RND)
2314
			mc = prandom_u32() % pkt_dev->src_mac_count;
Luiz Capitulino's avatar
Luiz Capitulino committed
2315 2316
		else {
			mc = pkt_dev->cur_src_mac_offset++;
Robert Olsson's avatar
Robert Olsson committed
2317
			if (pkt_dev->cur_src_mac_offset >=
Luiz Capitulino's avatar
Luiz Capitulino committed
2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339
			    pkt_dev->src_mac_count)
				pkt_dev->cur_src_mac_offset = 0;
		}

		tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
		pkt_dev->hh[11] = tmp;
		tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
		pkt_dev->hh[10] = tmp;
		tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
		pkt_dev->hh[9] = tmp;
		tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
		pkt_dev->hh[8] = tmp;
		tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
		pkt_dev->hh[7] = tmp;
	}

	/*  Deal with Destination MAC */
	if (pkt_dev->dst_mac_count > 1) {
		__u32 mc;
		__u32 tmp;

		if (pkt_dev->flags & F_MACDST_RND)
2340
			mc = prandom_u32() % pkt_dev->dst_mac_count;
Luiz Capitulino's avatar
Luiz Capitulino committed
2341 2342 2343

		else {
			mc = pkt_dev->cur_dst_mac_offset++;
Robert Olsson's avatar
Robert Olsson committed
2344
			if (pkt_dev->cur_dst_mac_offset >=
Luiz Capitulino's avatar
Luiz Capitulino committed
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361
			    pkt_dev->dst_mac_count) {
				pkt_dev->cur_dst_mac_offset = 0;
			}
		}

		tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
		pkt_dev->hh[5] = tmp;
		tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
		pkt_dev->hh[4] = tmp;
		tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
		pkt_dev->hh[3] = tmp;
		tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
		pkt_dev->hh[2] = tmp;
		tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
		pkt_dev->hh[1] = tmp;
	}

2362
	if (pkt_dev->flags & F_MPLS_RND) {
2363
		unsigned int i;
2364
		for (i = 0; i < pkt_dev->nr_labels; i++)
2365 2366
			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
2367
					     ((__force __be32)prandom_u32() &
2368 2369 2370
						      htonl(0x000fffff));
	}

Francesco Fondelli's avatar
Francesco Fondelli committed
2371
	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
2372
		pkt_dev->vlan_id = prandom_u32() & (4096 - 1);
Francesco Fondelli's avatar
Francesco Fondelli committed
2373 2374 2375
	}

	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
2376
		pkt_dev->svlan_id = prandom_u32() & (4096 - 1);
Francesco Fondelli's avatar
Francesco Fondelli committed
2377 2378
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
2379 2380
	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
		if (pkt_dev->flags & F_UDPSRC_RND)
2381
			pkt_dev->cur_udp_src = prandom_u32() %
Stephen Hemminger's avatar
Stephen Hemminger committed
2382 2383
				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
				+ pkt_dev->udp_src_min;
Luiz Capitulino's avatar
Luiz Capitulino committed
2384 2385

		else {
Linus Torvalds's avatar
Linus Torvalds committed
2386 2387 2388
			pkt_dev->cur_udp_src++;
			if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
				pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
Luiz Capitulino's avatar
Luiz Capitulino committed
2389 2390 2391 2392 2393
		}
	}

	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
		if (pkt_dev->flags & F_UDPDST_RND) {
2394
			pkt_dev->cur_udp_dst = prandom_u32() %
Stephen Hemminger's avatar
Stephen Hemminger committed
2395 2396
				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
				+ pkt_dev->udp_dst_min;
Luiz Capitulino's avatar
Luiz Capitulino committed
2397
		} else {
Linus Torvalds's avatar
Linus Torvalds committed
2398
			pkt_dev->cur_udp_dst++;
Luiz Capitulino's avatar
Luiz Capitulino committed
2399
			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
Linus Torvalds's avatar
Linus Torvalds committed
2400
				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
Luiz Capitulino's avatar
Luiz Capitulino committed
2401 2402
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
2403 2404 2405

	if (!(pkt_dev->flags & F_IPV6)) {

2406 2407 2408
		imn = ntohl(pkt_dev->saddr_min);
		imx = ntohl(pkt_dev->saddr_max);
		if (imn < imx) {
Linus Torvalds's avatar
Linus Torvalds committed
2409
			__u32 t;
Luiz Capitulino's avatar
Luiz Capitulino committed
2410
			if (pkt_dev->flags & F_IPSRC_RND)
2411
				t = prandom_u32() % (imx - imn) + imn;
Linus Torvalds's avatar
Linus Torvalds committed
2412 2413 2414
			else {
				t = ntohl(pkt_dev->cur_saddr);
				t++;
2415
				if (t > imx)
Linus Torvalds's avatar
Linus Torvalds committed
2416
					t = imn;
2417

Linus Torvalds's avatar
Linus Torvalds committed
2418 2419 2420
			}
			pkt_dev->cur_saddr = htonl(t);
		}
Luiz Capitulino's avatar
Luiz Capitulino committed
2421

2422
		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
Linus Torvalds's avatar
Linus Torvalds committed
2423 2424
			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
		} else {
Al Viro's avatar
Al Viro committed
2425 2426 2427
			imn = ntohl(pkt_dev->daddr_min);
			imx = ntohl(pkt_dev->daddr_max);
			if (imn < imx) {
Linus Torvalds's avatar
Linus Torvalds committed
2428
				__u32 t;
Al Viro's avatar
Al Viro committed
2429
				__be32 s;
Linus Torvalds's avatar
Linus Torvalds committed
2430 2431
				if (pkt_dev->flags & F_IPDST_RND) {

2432
					do {
2433 2434
						t = prandom_u32() %
							(imx - imn) + imn;
Al Viro's avatar
Al Viro committed
2435
						s = htonl(t);
2436 2437 2438 2439 2440
					} while (ipv4_is_loopback(s) ||
						ipv4_is_multicast(s) ||
						ipv4_is_lbcast(s) ||
						ipv4_is_zeronet(s) ||
						ipv4_is_local_multicast(s));
Al Viro's avatar
Al Viro committed
2441 2442
					pkt_dev->cur_daddr = s;
				} else {
Linus Torvalds's avatar
Linus Torvalds committed
2443 2444 2445 2446 2447 2448 2449 2450
					t = ntohl(pkt_dev->cur_daddr);
					t++;
					if (t > imx) {
						t = imn;
					}
					pkt_dev->cur_daddr = htonl(t);
				}
			}
Luiz Capitulino's avatar
Luiz Capitulino committed
2451
			if (pkt_dev->cflows) {
2452
				pkt_dev->flows[flow].flags |= F_INIT;
Luiz Capitulino's avatar
Luiz Capitulino committed
2453 2454
				pkt_dev->flows[flow].cur_daddr =
				    pkt_dev->cur_daddr;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2455
#ifdef CONFIG_XFRM
2456
				if (pkt_dev->flags & F_IPSEC)
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2457 2458
					get_ipsec_sa(pkt_dev, flow);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2459 2460 2461
				pkt_dev->nflows++;
			}
		}
Luiz Capitulino's avatar
Luiz Capitulino committed
2462 2463
	} else {		/* IPV6 * */

Joe Perches's avatar
Joe Perches committed
2464
		if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) {
Linus Torvalds's avatar
Linus Torvalds committed
2465 2466 2467 2468
			int i;

			/* Only random destinations yet */

Luiz Capitulino's avatar
Luiz Capitulino committed
2469
			for (i = 0; i < 4; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
2470
				pkt_dev->cur_in6_daddr.s6_addr32[i] =
2471
				    (((__force __be32)prandom_u32() |
Luiz Capitulino's avatar
Luiz Capitulino committed
2472 2473
				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
				     pkt_dev->max_in6_daddr.s6_addr32[i]);
Linus Torvalds's avatar
Linus Torvalds committed
2474
			}
Luiz Capitulino's avatar
Luiz Capitulino committed
2475
		}
Linus Torvalds's avatar
Linus Torvalds committed
2476 2477
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
2478 2479 2480
	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
		__u32 t;
		if (pkt_dev->flags & F_TXSIZE_RND) {
2481
			t = prandom_u32() %
Stephen Hemminger's avatar
Stephen Hemminger committed
2482 2483
				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
				+ pkt_dev->min_pkt_size;
Luiz Capitulino's avatar
Luiz Capitulino committed
2484
		} else {
Linus Torvalds's avatar
Linus Torvalds committed
2485
			t = pkt_dev->cur_pkt_size + 1;
Luiz Capitulino's avatar
Luiz Capitulino committed
2486
			if (t > pkt_dev->max_pkt_size)
Linus Torvalds's avatar
Linus Torvalds committed
2487
				t = pkt_dev->min_pkt_size;
Luiz Capitulino's avatar
Luiz Capitulino committed
2488 2489 2490
		}
		pkt_dev->cur_pkt_size = t;
	}
Linus Torvalds's avatar
Linus Torvalds committed
2491

2492
	set_cur_queue_map(pkt_dev);
2493

Linus Torvalds's avatar
Linus Torvalds committed
2494 2495 2496
	pkt_dev->flows[flow].count++;
}

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2497 2498

#ifdef CONFIG_XFRM
2499
static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
2500 2501 2502 2503

	[RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
};

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2504 2505 2506 2507
static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
{
	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
	int err = 0;
2508
	struct net *net = dev_net(pkt_dev->odev);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2509 2510 2511 2512 2513

	if (!x)
		return 0;
	/* XXX: we dont support tunnel mode for now until
	 * we resolve the dst issue */
2514
	if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2515 2516
		return 0;

2517 2518 2519 2520
	/* But when user specify an valid SPI, transformation
	 * supports both transport/tunnel mode + ESP/AH type.
	 */
	if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
2521
		skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF;
2522 2523

	rcu_read_lock_bh();
2524
	err = x->outer_mode->output(x, skb);
2525
	rcu_read_unlock_bh();
2526 2527
	if (err) {
		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2528
		goto error;
2529
	}
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2530
	err = x->type->output(x, skb);
2531 2532
	if (err) {
		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2533
		goto error;
2534
	}
2535
	spin_lock_bh(&x->lock);
2536
	x->curlft.bytes += skb->len;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2537
	x->curlft.packets++;
2538
	spin_unlock_bh(&x->lock);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2539 2540 2541 2542
error:
	return err;
}

Stephen Hemminger's avatar
Stephen Hemminger committed
2543
static void free_SAs(struct pktgen_dev *pkt_dev)
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2544 2545 2546
{
	if (pkt_dev->cflows) {
		/* let go of the SAs if we have them */
2547 2548
		int i;
		for (i = 0; i < pkt_dev->cflows; i++) {
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2549 2550 2551 2552 2553 2554 2555 2556 2557
			struct xfrm_state *x = pkt_dev->flows[i].x;
			if (x) {
				xfrm_state_put(x);
				pkt_dev->flows[i].x = NULL;
			}
		}
	}
}

Stephen Hemminger's avatar
Stephen Hemminger committed
2558
static int process_ipsec(struct pktgen_dev *pkt_dev,
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2559 2560
			      struct sk_buff *skb, __be16 protocol)
{
2561
	if (pkt_dev->flags & F_IPSEC) {
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2562 2563 2564
		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
		int nhead = 0;
		if (x) {
2565
			struct ethhdr *eth;
2566
			struct iphdr *iph;
2567
			int ret;
2568

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2569
			nhead = x->props.header_len - skb_headroom(skb);
2570
			if (nhead > 0) {
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2571 2572
				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
				if (ret < 0) {
2573 2574
					pr_err("Error expanding ipsec packet %d\n",
					       ret);
2575
					goto err;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2576 2577 2578 2579 2580 2581 2582
				}
			}

			/* ipsec is not expecting ll header */
			skb_pull(skb, ETH_HLEN);
			ret = pktgen_output_ipsec(skb, pkt_dev);
			if (ret) {
2583
				pr_err("Error creating ipsec packet %d\n", ret);
2584
				goto err;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2585 2586
			}
			/* restore ll */
2587
			eth = skb_push(skb, ETH_HLEN);
2588 2589
			memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN);
			eth->h_proto = protocol;
2590 2591 2592 2593 2594

			/* Update IPv4 header len as well as checksum value */
			iph = ip_hdr(skb);
			iph->tot_len = htons(skb->len - ETH_HLEN);
			ip_send_check(iph);
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2595 2596 2597
		}
	}
	return 1;
2598 2599 2600
err:
	kfree_skb(skb);
	return 0;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2601 2602 2603
}
#endif

2604 2605
static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
2606
	unsigned int i;
2607
	for (i = 0; i < pkt_dev->nr_labels; i++)
2608
		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
2609

2610 2611 2612 2613
	mpls--;
	*mpls |= MPLS_STACK_BOTTOM;
}

Al Viro's avatar
Al Viro committed
2614 2615 2616 2617 2618 2619
static inline __be16 build_tci(unsigned int id, unsigned int cfi,
			       unsigned int prio)
{
	return htons(id | (cfi << 12) | (prio << 13));
}

2620 2621 2622
static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
				int datalen)
{
2623
	struct timespec64 timestamp;
2624 2625
	struct pktgen_hdr *pgh;

2626
	pgh = skb_put(skb, sizeof(*pgh));
2627 2628 2629
	datalen -= sizeof(*pgh);

	if (pkt_dev->nfrags <= 0) {
2630
		skb_put_zero(skb, datalen);
2631 2632 2633
	} else {
		int frags = pkt_dev->nfrags;
		int i, len;
2634
		int frag_len;
2635 2636 2637 2638 2639 2640


		if (frags > MAX_SKB_FRAGS)
			frags = MAX_SKB_FRAGS;
		len = datalen - frags * PAGE_SIZE;
		if (len > 0) {
2641
			skb_put_zero(skb, len);
2642 2643 2644 2645
			datalen = frags * PAGE_SIZE;
		}

		i = 0;
2646 2647
		frag_len = (datalen/frags) < PAGE_SIZE ?
			   (datalen/frags) : PAGE_SIZE;
2648 2649 2650 2651 2652 2653 2654 2655 2656 2657
		while (datalen > 0) {
			if (unlikely(!pkt_dev->page)) {
				int node = numa_node_id();

				if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
					node = pkt_dev->node;
				pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
				if (!pkt_dev->page)
					break;
			}
2658
			get_page(pkt_dev->page);
2659
			skb_frag_set_page(skb, i, pkt_dev->page);
2660
			skb_shinfo(skb)->frags[i].page_offset = 0;
2661 2662
			/*last fragment, fill rest of data*/
			if (i == (frags - 1))
2663 2664
				skb_frag_size_set(&skb_shinfo(skb)->frags[i],
				    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE));
2665
			else
2666 2667 2668 2669
				skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len);
			datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
			skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
			skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}
	}

	/* Stamp the time, and sequence number,
	 * convert them to network byte order
	 */
	pgh->pgh_magic = htonl(PKTGEN_MAGIC);
	pgh->seq_num = htonl(pkt_dev->seq_num);

2681 2682 2683 2684
	if (pkt_dev->flags & F_NO_TIMESTAMP) {
		pgh->tv_sec = 0;
		pgh->tv_usec = 0;
	} else {
2685 2686 2687 2688 2689 2690 2691 2692 2693
		/*
		 * pgh->tv_sec wraps in y2106 when interpreted as unsigned
		 * as done by wireshark, or y2038 when interpreted as signed.
		 * This is probably harmless, but if anyone wants to improve
		 * it, we could introduce a variant that puts 64-bit nanoseconds
		 * into the respective header bytes.
		 * This would also be slightly faster to read.
		 */
		ktime_get_real_ts64(&timestamp);
2694
		pgh->tv_sec = htonl(timestamp.tv_sec);
2695
		pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC);
2696
	}
2697 2698
}

2699
static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
Paolo Abeni's avatar
Paolo Abeni committed
2700
					struct pktgen_dev *pkt_dev)
2701
{
Paolo Abeni's avatar
Paolo Abeni committed
2702
	unsigned int extralen = LL_RESERVED_SPACE(dev);
2703
	struct sk_buff *skb = NULL;
Paolo Abeni's avatar
Paolo Abeni committed
2704
	unsigned int size;
2705

Paolo Abeni's avatar
Paolo Abeni committed
2706
	size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead;
2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717
	if (pkt_dev->flags & F_NODE) {
		int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();

		skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node);
		if (likely(skb)) {
			skb_reserve(skb, NET_SKB_PAD);
			skb->dev = dev;
		}
	} else {
		 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
	}
2718

Paolo Abeni's avatar
Paolo Abeni committed
2719
	/* the caller pre-fetches from skb->data and reserves for the mac hdr */
2720
	if (likely(skb))
Paolo Abeni's avatar
Paolo Abeni committed
2721
		skb_reserve(skb, extralen - 16);
2722 2723 2724 2725

	return skb;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
2726 2727
static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
					struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
2728 2729 2730 2731 2732 2733
{
	struct sk_buff *skb = NULL;
	__u8 *eth;
	struct udphdr *udph;
	int datalen, iplen;
	struct iphdr *iph;
2734
	__be16 protocol = htons(ETH_P_IP);
2735
	__be32 *mpls;
Francesco Fondelli's avatar
Francesco Fondelli committed
2736 2737 2738 2739
	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2740
	u16 queue_map;
2741 2742

	if (pkt_dev->nr_labels)
2743
		protocol = htons(ETH_P_MPLS_UC);
Luiz Capitulino's avatar
Luiz Capitulino committed
2744

Francesco Fondelli's avatar
Francesco Fondelli committed
2745
	if (pkt_dev->vlan_id != 0xffff)
2746
		protocol = htons(ETH_P_8021Q);
Francesco Fondelli's avatar
Francesco Fondelli committed
2747

2748 2749 2750 2751
	/* Update any of the values, used when we're incrementing various
	 * fields.
	 */
	mod_cur_headers(pkt_dev);
2752
	queue_map = pkt_dev->cur_queue_map;
2753

Paolo Abeni's avatar
Paolo Abeni committed
2754
	skb = pktgen_alloc_skb(odev, pkt_dev);
Linus Torvalds's avatar
Linus Torvalds committed
2755 2756 2757 2758 2759
	if (!skb) {
		sprintf(pkt_dev->result, "No memory");
		return NULL;
	}

2760
	prefetchw(skb->data);
Paolo Abeni's avatar
Paolo Abeni committed
2761
	skb_reserve(skb, 16);
Linus Torvalds's avatar
Linus Torvalds committed
2762 2763

	/*  Reserve for ethernet and IP header  */
2764
	eth = skb_push(skb, 14);
2765
	mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32));
2766 2767
	if (pkt_dev->nr_labels)
		mpls_push(mpls, pkt_dev);
Francesco Fondelli's avatar
Francesco Fondelli committed
2768 2769

	if (pkt_dev->vlan_id != 0xffff) {
2770
		if (pkt_dev->svlan_id != 0xffff) {
2771
			svlan_tci = skb_put(skb, sizeof(__be16));
Al Viro's avatar
Al Viro committed
2772 2773 2774
			*svlan_tci = build_tci(pkt_dev->svlan_id,
					       pkt_dev->svlan_cfi,
					       pkt_dev->svlan_p);
2775 2776
			svlan_encapsulated_proto = skb_put(skb,
							   sizeof(__be16));
2777
			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
Francesco Fondelli's avatar
Francesco Fondelli committed
2778
		}
2779
		vlan_tci = skb_put(skb, sizeof(__be16));
Al Viro's avatar
Al Viro committed
2780 2781 2782
		*vlan_tci = build_tci(pkt_dev->vlan_id,
				      pkt_dev->vlan_cfi,
				      pkt_dev->vlan_p);
2783
		vlan_encapsulated_proto = skb_put(skb, sizeof(__be16));
2784
		*vlan_encapsulated_proto = htons(ETH_P_IP);
Francesco Fondelli's avatar
Francesco Fondelli committed
2785 2786
	}

2787
	skb_reset_mac_header(skb);
2788
	skb_set_network_header(skb, skb->len);
2789
	iph = skb_put(skb, sizeof(struct iphdr));
2790 2791

	skb_set_transport_header(skb, skb->len);
2792
	udph = skb_put(skb, sizeof(struct udphdr));
2793
	skb_set_queue_mapping(skb, queue_map);
2794 2795
	skb->priority = pkt_dev->skb_priority;

Linus Torvalds's avatar
Linus Torvalds committed
2796
	memcpy(eth, pkt_dev->hh, 12);
Al Viro's avatar
Al Viro committed
2797
	*(__be16 *) & eth[12] = protocol;
Linus Torvalds's avatar
Linus Torvalds committed
2798

2799 2800
	/* Eth + IPh + UDPh + mpls */
	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
2801
		  pkt_dev->pkt_overhead;
2802
	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr))
Linus Torvalds's avatar
Linus Torvalds committed
2803
		datalen = sizeof(struct pktgen_hdr);
Luiz Capitulino's avatar
Luiz Capitulino committed
2804

Linus Torvalds's avatar
Linus Torvalds committed
2805 2806
	udph->source = htons(pkt_dev->cur_udp_src);
	udph->dest = htons(pkt_dev->cur_udp_dst);
Luiz Capitulino's avatar
Luiz Capitulino committed
2807
	udph->len = htons(datalen + 8);	/* DATA + udphdr */
2808
	udph->check = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2809 2810 2811 2812

	iph->ihl = 5;
	iph->version = 4;
	iph->ttl = 32;
Francesco Fondelli's avatar
Francesco Fondelli committed
2813
	iph->tos = pkt_dev->tos;
Luiz Capitulino's avatar
Luiz Capitulino committed
2814
	iph->protocol = IPPROTO_UDP;	/* UDP */
Linus Torvalds's avatar
Linus Torvalds committed
2815 2816
	iph->saddr = pkt_dev->cur_saddr;
	iph->daddr = pkt_dev->cur_daddr;
2817 2818
	iph->id = htons(pkt_dev->ip_id);
	pkt_dev->ip_id++;
Linus Torvalds's avatar
Linus Torvalds committed
2819 2820 2821
	iph->frag_off = 0;
	iplen = 20 + 8 + datalen;
	iph->tot_len = htons(iplen);
2822
	ip_send_check(iph);
2823
	skb->protocol = protocol;
Linus Torvalds's avatar
Linus Torvalds committed
2824 2825
	skb->dev = odev;
	skb->pkt_type = PACKET_HOST;
2826

2827 2828
	pktgen_finalize_skb(pkt_dev, skb, datalen);

2829 2830
	if (!(pkt_dev->flags & F_UDPCSUM)) {
		skb->ip_summed = CHECKSUM_NONE;
2831
	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) {
2832 2833
		skb->ip_summed = CHECKSUM_PARTIAL;
		skb->csum = 0;
2834
		udp4_hwcsum(skb, iph->saddr, iph->daddr);
2835
	} else {
2836
		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0);
2837 2838

		/* add protocol-dependent pseudo-header */
2839
		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
2840 2841 2842 2843 2844 2845
						datalen + 8, IPPROTO_UDP, csum);

		if (udph->check == 0)
			udph->check = CSUM_MANGLED_0;
	}

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
2846 2847 2848 2849 2850
#ifdef CONFIG_XFRM
	if (!process_ipsec(pkt_dev, skb, protocol))
		return NULL;
#endif

Linus Torvalds's avatar
Linus Torvalds committed
2851 2852 2853
	return skb;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
2854 2855
static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
					struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
2856 2857 2858 2859
{
	struct sk_buff *skb = NULL;
	__u8 *eth;
	struct udphdr *udph;
2860
	int datalen, udplen;
Linus Torvalds's avatar
Linus Torvalds committed
2861
	struct ipv6hdr *iph;
2862
	__be16 protocol = htons(ETH_P_IPV6);
2863
	__be32 *mpls;
Francesco Fondelli's avatar
Francesco Fondelli committed
2864 2865 2866 2867
	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2868
	u16 queue_map;
2869 2870

	if (pkt_dev->nr_labels)
2871
		protocol = htons(ETH_P_MPLS_UC);
2872

Francesco Fondelli's avatar
Francesco Fondelli committed
2873
	if (pkt_dev->vlan_id != 0xffff)
2874
		protocol = htons(ETH_P_8021Q);
Francesco Fondelli's avatar
Francesco Fondelli committed
2875

2876 2877 2878 2879
	/* Update any of the values, used when we're incrementing various
	 * fields.
	 */
	mod_cur_headers(pkt_dev);
2880
	queue_map = pkt_dev->cur_queue_map;
2881

Paolo Abeni's avatar
Paolo Abeni committed
2882
	skb = pktgen_alloc_skb(odev, pkt_dev);
Linus Torvalds's avatar
Linus Torvalds committed
2883 2884 2885 2886 2887
	if (!skb) {
		sprintf(pkt_dev->result, "No memory");
		return NULL;
	}

2888
	prefetchw(skb->data);
Linus Torvalds's avatar
Linus Torvalds committed
2889 2890 2891
	skb_reserve(skb, 16);

	/*  Reserve for ethernet and IP header  */
2892
	eth = skb_push(skb, 14);
2893
	mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32));
2894 2895
	if (pkt_dev->nr_labels)
		mpls_push(mpls, pkt_dev);
Francesco Fondelli's avatar
Francesco Fondelli committed
2896 2897

	if (pkt_dev->vlan_id != 0xffff) {
2898
		if (pkt_dev->svlan_id != 0xffff) {
2899
			svlan_tci = skb_put(skb, sizeof(__be16));
Al Viro's avatar
Al Viro committed
2900 2901 2902
			*svlan_tci = build_tci(pkt_dev->svlan_id,
					       pkt_dev->svlan_cfi,
					       pkt_dev->svlan_p);
2903 2904
			svlan_encapsulated_proto = skb_put(skb,
							   sizeof(__be16));
2905
			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
Francesco Fondelli's avatar
Francesco Fondelli committed
2906
		}
2907
		vlan_tci = skb_put(skb, sizeof(__be16));
Al Viro's avatar
Al Viro committed
2908 2909 2910
		*vlan_tci = build_tci(pkt_dev->vlan_id,
				      pkt_dev->vlan_cfi,
				      pkt_dev->vlan_p);
2911
		vlan_encapsulated_proto = skb_put(skb, sizeof(__be16));
2912
		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
Francesco Fondelli's avatar
Francesco Fondelli committed
2913 2914
	}

2915
	skb_reset_mac_header(skb);
2916
	skb_set_network_header(skb, skb->len);
2917
	iph = skb_put(skb, sizeof(struct ipv6hdr));
2918 2919

	skb_set_transport_header(skb, skb->len);
2920
	udph = skb_put(skb, sizeof(struct udphdr));
2921
	skb_set_queue_mapping(skb, queue_map);
2922
	skb->priority = pkt_dev->skb_priority;
Linus Torvalds's avatar
Linus Torvalds committed
2923 2924

	memcpy(eth, pkt_dev->hh, 12);
2925
	*(__be16 *) &eth[12] = protocol;
2926

2927 2928 2929
	/* Eth + IPh + UDPh + mpls */
	datalen = pkt_dev->cur_pkt_size - 14 -
		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
2930
		  pkt_dev->pkt_overhead;
Linus Torvalds's avatar
Linus Torvalds committed
2931

2932
	if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) {
Linus Torvalds's avatar
Linus Torvalds committed
2933
		datalen = sizeof(struct pktgen_hdr);
2934
		net_info_ratelimited("increased datalen to %d\n", datalen);
Linus Torvalds's avatar
Linus Torvalds committed
2935 2936
	}

2937
	udplen = datalen + sizeof(struct udphdr);
Linus Torvalds's avatar
Linus Torvalds committed
2938 2939
	udph->source = htons(pkt_dev->cur_udp_src);
	udph->dest = htons(pkt_dev->cur_udp_dst);
2940 2941
	udph->len = htons(udplen);
	udph->check = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2942

2943
	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
Linus Torvalds's avatar
Linus Torvalds committed
2944

Francesco Fondelli's avatar
Francesco Fondelli committed
2945 2946
	if (pkt_dev->traffic_class) {
		/* Version + traffic class + flow (0) */
Al Viro's avatar
Al Viro committed
2947
		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
Francesco Fondelli's avatar
Francesco Fondelli committed
2948 2949
	}

Linus Torvalds's avatar
Linus Torvalds committed
2950 2951
	iph->hop_limit = 32;

2952
	iph->payload_len = htons(udplen);
Linus Torvalds's avatar
Linus Torvalds committed
2953 2954
	iph->nexthdr = IPPROTO_UDP;

2955 2956
	iph->daddr = pkt_dev->cur_in6_daddr;
	iph->saddr = pkt_dev->cur_in6_saddr;
Linus Torvalds's avatar
Linus Torvalds committed
2957

2958
	skb->protocol = protocol;
Linus Torvalds's avatar
Linus Torvalds committed
2959 2960 2961
	skb->dev = odev;
	skb->pkt_type = PACKET_HOST;

2962 2963
	pktgen_finalize_skb(pkt_dev, skb, datalen);

2964 2965
	if (!(pkt_dev->flags & F_UDPCSUM)) {
		skb->ip_summed = CHECKSUM_NONE;
2966
	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) {
2967 2968 2969 2970 2971
		skb->ip_summed = CHECKSUM_PARTIAL;
		skb->csum_start = skb_transport_header(skb) - skb->head;
		skb->csum_offset = offsetof(struct udphdr, check);
		udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
	} else {
2972
		__wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0);
2973 2974 2975 2976 2977 2978 2979 2980

		/* add protocol-dependent pseudo-header */
		udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);

		if (udph->check == 0)
			udph->check = CSUM_MANGLED_0;
	}

Linus Torvalds's avatar
Linus Torvalds committed
2981 2982 2983
	return skb;
}

Stephen Hemminger's avatar
Stephen Hemminger committed
2984 2985
static struct sk_buff *fill_packet(struct net_device *odev,
				   struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
2986
{
Luiz Capitulino's avatar
Luiz Capitulino committed
2987
	if (pkt_dev->flags & F_IPV6)
Linus Torvalds's avatar
Linus Torvalds committed
2988 2989 2990 2991 2992
		return fill_packet_ipv6(odev, pkt_dev);
	else
		return fill_packet_ipv4(odev, pkt_dev);
}

Luiz Capitulino's avatar
Luiz Capitulino committed
2993
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
2994
{
Luiz Capitulino's avatar
Luiz Capitulino committed
2995 2996
	pkt_dev->seq_num = 1;
	pkt_dev->idle_acc = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2997
	pkt_dev->sofar = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
2998 2999
	pkt_dev->tx_bytes = 0;
	pkt_dev->errors = 0;
Linus Torvalds's avatar
Linus Torvalds committed
3000 3001 3002 3003 3004 3005
}

/* Set up structure for sending pkts, clear counters */

static void pktgen_run(struct pktgen_thread *t)
{
3006
	struct pktgen_dev *pkt_dev;
Linus Torvalds's avatar
Linus Torvalds committed
3007 3008
	int started = 0;

3009
	func_enter();
Linus Torvalds's avatar
Linus Torvalds committed
3010

3011 3012
	rcu_read_lock();
	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
Linus Torvalds's avatar
Linus Torvalds committed
3013 3014 3015 3016 3017 3018

		/*
		 * setup odev and create initial packet.
		 */
		pktgen_setup_inject(pkt_dev);

Luiz Capitulino's avatar
Luiz Capitulino committed
3019
		if (pkt_dev->odev) {
Linus Torvalds's avatar
Linus Torvalds committed
3020 3021
			pktgen_clear_counters(pkt_dev);
			pkt_dev->skb = NULL;
3022
			pkt_dev->started_at = pkt_dev->next_tx = ktime_get();
3023

3024
			set_pkt_overhead(pkt_dev);
Luiz Capitulino's avatar
Luiz Capitulino committed
3025

Linus Torvalds's avatar
Linus Torvalds committed
3026
			strcpy(pkt_dev->result, "Starting");
3027
			pkt_dev->running = 1;	/* Cranke yeself! */
Linus Torvalds's avatar
Linus Torvalds committed
3028
			started++;
Luiz Capitulino's avatar
Luiz Capitulino committed
3029
		} else
Linus Torvalds's avatar
Linus Torvalds committed
3030 3031
			strcpy(pkt_dev->result, "Error starting");
	}
3032
	rcu_read_unlock();
Luiz Capitulino's avatar
Luiz Capitulino committed
3033 3034
	if (started)
		t->control &= ~(T_STOP);
Linus Torvalds's avatar
Linus Torvalds committed
3035 3036
}

Cong Wang's avatar
Cong Wang committed
3037
static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn)
Linus Torvalds's avatar
Linus Torvalds committed
3038
{
3039
	struct pktgen_thread *t;
Linus Torvalds's avatar
Linus Torvalds committed
3040

3041
	func_enter();
Linus Torvalds's avatar
Linus Torvalds committed
3042

3043
	mutex_lock(&pktgen_thread_lock);
3044

Cong Wang's avatar
Cong Wang committed
3045
	list_for_each_entry(t, &pn->pktgen_threads, th_list)
3046
		t->control |= T_STOP;
3047

3048
	mutex_unlock(&pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
3049 3050
}

Stephen Hemminger's avatar
Stephen Hemminger committed
3051
static int thread_is_running(const struct pktgen_thread *t)
Linus Torvalds's avatar
Linus Torvalds committed
3052
{
Stephen Hemminger's avatar
Stephen Hemminger committed
3053
	const struct pktgen_dev *pkt_dev;
Linus Torvalds's avatar
Linus Torvalds committed
3054

3055 3056 3057 3058
	rcu_read_lock();
	list_for_each_entry_rcu(pkt_dev, &t->if_list, list)
		if (pkt_dev->running) {
			rcu_read_unlock();
Stephen Hemminger's avatar
Stephen Hemminger committed
3059
			return 1;
3060 3061
		}
	rcu_read_unlock();
Stephen Hemminger's avatar
Stephen Hemminger committed
3062
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3063 3064
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3065
static int pktgen_wait_thread_run(struct pktgen_thread *t)
Linus Torvalds's avatar
Linus Torvalds committed
3066
{
Luiz Capitulino's avatar
Luiz Capitulino committed
3067
	while (thread_is_running(t)) {
Linus Torvalds's avatar
Linus Torvalds committed
3068

Luiz Capitulino's avatar
Luiz Capitulino committed
3069
		msleep_interruptible(100);
Linus Torvalds's avatar
Linus Torvalds committed
3070

Luiz Capitulino's avatar
Luiz Capitulino committed
3071 3072 3073 3074 3075 3076
		if (signal_pending(current))
			goto signal;
	}
	return 1;
signal:
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3077 3078
}

Cong Wang's avatar
Cong Wang committed
3079
static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
Linus Torvalds's avatar
Linus Torvalds committed
3080
{
3081
	struct pktgen_thread *t;
Linus Torvalds's avatar
Linus Torvalds committed
3082
	int sig = 1;
Luiz Capitulino's avatar
Luiz Capitulino committed
3083

3084
	mutex_lock(&pktgen_thread_lock);
3085

Cong Wang's avatar
Cong Wang committed
3086
	list_for_each_entry(t, &pn->pktgen_threads, th_list) {
Linus Torvalds's avatar
Linus Torvalds committed
3087
		sig = pktgen_wait_thread_run(t);
Luiz Capitulino's avatar
Luiz Capitulino committed
3088 3089
		if (sig == 0)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
3090
	}
3091 3092

	if (sig == 0)
Cong Wang's avatar
Cong Wang committed
3093
		list_for_each_entry(t, &pn->pktgen_threads, th_list)
Linus Torvalds's avatar
Linus Torvalds committed
3094
			t->control |= (T_STOP);
3095

3096
	mutex_unlock(&pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
3097 3098 3099
	return sig;
}

Cong Wang's avatar
Cong Wang committed
3100
static void pktgen_run_all_threads(struct pktgen_net *pn)
Linus Torvalds's avatar
Linus Torvalds committed
3101
{
3102
	struct pktgen_thread *t;
Linus Torvalds's avatar
Linus Torvalds committed
3103

3104
	func_enter();
Linus Torvalds's avatar
Linus Torvalds committed
3105

3106
	mutex_lock(&pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
3107

Cong Wang's avatar
Cong Wang committed
3108
	list_for_each_entry(t, &pn->pktgen_threads, th_list)
Linus Torvalds's avatar
Linus Torvalds committed
3109
		t->control |= (T_RUN);
3110

3111
	mutex_unlock(&pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
3112

3113 3114
	/* Propagate thread->control  */
	schedule_timeout_interruptible(msecs_to_jiffies(125));
Luiz Capitulino's avatar
Luiz Capitulino committed
3115

Cong Wang's avatar
Cong Wang committed
3116
	pktgen_wait_all_threads_run(pn);
Linus Torvalds's avatar
Linus Torvalds committed
3117 3118
}

Cong Wang's avatar
Cong Wang committed
3119
static void pktgen_reset_all_threads(struct pktgen_net *pn)
3120 3121 3122
{
	struct pktgen_thread *t;

3123
	func_enter();
3124 3125 3126

	mutex_lock(&pktgen_thread_lock);

Cong Wang's avatar
Cong Wang committed
3127
	list_for_each_entry(t, &pn->pktgen_threads, th_list)
3128 3129 3130 3131
		t->control |= (T_REMDEVALL);

	mutex_unlock(&pktgen_thread_lock);

3132 3133
	/* Propagate thread->control  */
	schedule_timeout_interruptible(msecs_to_jiffies(125));
3134

Cong Wang's avatar
Cong Wang committed
3135
	pktgen_wait_all_threads_run(pn);
3136 3137
}

Linus Torvalds's avatar
Linus Torvalds committed
3138 3139
static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
{
3140
	__u64 bps, mbps, pps;
Luiz Capitulino's avatar
Luiz Capitulino committed
3141
	char *p = pkt_dev->result;
3142 3143 3144 3145
	ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
				    pkt_dev->started_at);
	ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);

3146
	p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
3147 3148 3149
		     (unsigned long long)ktime_to_us(elapsed),
		     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
		     (unsigned long long)ktime_to_us(idle),
Luiz Capitulino's avatar
Luiz Capitulino committed
3150 3151 3152
		     (unsigned long long)pkt_dev->sofar,
		     pkt_dev->cur_pkt_size, nr_frags);

3153 3154
	pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
			ktime_to_ns(elapsed));
Luiz Capitulino's avatar
Luiz Capitulino committed
3155 3156 3157 3158 3159 3160 3161 3162 3163 3164

	bps = pps * 8 * pkt_dev->cur_pkt_size;

	mbps = bps;
	do_div(mbps, 1000000);
	p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
		     (unsigned long long)pps,
		     (unsigned long long)mbps,
		     (unsigned long long)bps,
		     (unsigned long long)pkt_dev->errors);
Linus Torvalds's avatar
Linus Torvalds committed
3165 3166 3167
}

/* Set stopped-at timer, remove from running list, do counters & statistics */
Luiz Capitulino's avatar
Luiz Capitulino committed
3168
static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
3169
{
Luiz Capitulino's avatar
Luiz Capitulino committed
3170
	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
3171

Luiz Capitulino's avatar
Luiz Capitulino committed
3172
	if (!pkt_dev->running) {
3173 3174
		pr_warn("interface: %s is already stopped\n",
			pkt_dev->odevname);
Luiz Capitulino's avatar
Luiz Capitulino committed
3175 3176
		return -EINVAL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
3177

3178
	pkt_dev->running = 0;
3179 3180
	kfree_skb(pkt_dev->skb);
	pkt_dev->skb = NULL;
3181
	pkt_dev->stopped_at = ktime_get();
Linus Torvalds's avatar
Linus Torvalds committed
3182

3183
	show_results(pkt_dev, nr_frags);
Linus Torvalds's avatar
Linus Torvalds committed
3184

Luiz Capitulino's avatar
Luiz Capitulino committed
3185
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3186 3187
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3188
static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
Linus Torvalds's avatar
Linus Torvalds committed
3189
{
3190
	struct pktgen_dev *pkt_dev, *best = NULL;
Luiz Capitulino's avatar
Luiz Capitulino committed
3191

3192 3193
	rcu_read_lock();
	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3194
		if (!pkt_dev->running)
Luiz Capitulino's avatar
Luiz Capitulino committed
3195 3196
			continue;
		if (best == NULL)
3197
			best = pkt_dev;
3198
		else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0)
3199
			best = pkt_dev;
Linus Torvalds's avatar
Linus Torvalds committed
3200
	}
3201 3202
	rcu_read_unlock();

Luiz Capitulino's avatar
Luiz Capitulino committed
3203
	return best;
Linus Torvalds's avatar
Linus Torvalds committed
3204 3205
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3206 3207
static void pktgen_stop(struct pktgen_thread *t)
{
3208
	struct pktgen_dev *pkt_dev;
Linus Torvalds's avatar
Linus Torvalds committed
3209

3210
	func_enter();
Linus Torvalds's avatar
Linus Torvalds committed
3211

3212
	rcu_read_lock();
Linus Torvalds's avatar
Linus Torvalds committed
3213

3214
	list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
3215
		pktgen_stop_device(pkt_dev);
3216
	}
Linus Torvalds's avatar
Linus Torvalds committed
3217

3218
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
3219 3220
}

3221 3222 3223 3224 3225 3226
/*
 * one of our devices needs to be removed - find it
 * and remove it
 */
static void pktgen_rem_one_if(struct pktgen_thread *t)
{
3227 3228
	struct list_head *q, *n;
	struct pktgen_dev *cur;
3229

3230
	func_enter();
3231

3232 3233
	list_for_each_safe(q, n, &t->if_list) {
		cur = list_entry(q, struct pktgen_dev, list);
3234

Luiz Capitulino's avatar
Luiz Capitulino committed
3235 3236
		if (!cur->removal_mark)
			continue;
3237

3238
		kfree_skb(cur->skb);
3239 3240 3241 3242 3243 3244 3245 3246
		cur->skb = NULL;

		pktgen_remove_device(t, cur);

		break;
	}
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3247
static void pktgen_rem_all_ifs(struct pktgen_thread *t)
Linus Torvalds's avatar
Linus Torvalds committed
3248
{
3249 3250
	struct list_head *q, *n;
	struct pktgen_dev *cur;
Luiz Capitulino's avatar
Luiz Capitulino committed
3251

3252 3253
	func_enter();

Luiz Capitulino's avatar
Luiz Capitulino committed
3254
	/* Remove all devices, free mem */
3255

3256 3257
	list_for_each_safe(q, n, &t->if_list) {
		cur = list_entry(q, struct pktgen_dev, list);
3258

3259
		kfree_skb(cur->skb);
3260 3261
		cur->skb = NULL;

Linus Torvalds's avatar
Linus Torvalds committed
3262 3263 3264 3265
		pktgen_remove_device(t, cur);
	}
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3266
static void pktgen_rem_thread(struct pktgen_thread *t)
Linus Torvalds's avatar
Linus Torvalds committed
3267
{
Luiz Capitulino's avatar
Luiz Capitulino committed
3268
	/* Remove from the thread list */
Cong Wang's avatar
Cong Wang committed
3269
	remove_proc_entry(t->tsk->comm, t->net->proc_dir);
Linus Torvalds's avatar
Linus Torvalds committed
3270 3271
}

3272
static void pktgen_resched(struct pktgen_dev *pkt_dev)
3273
{
3274
	ktime_t idle_start = ktime_get();
3275
	schedule();
3276
	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
3277
}
3278

3279 3280
static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
{
3281
	ktime_t idle_start = ktime_get();
3282

3283
	while (refcount_read(&(pkt_dev->skb->users)) != 1) {
3284 3285 3286 3287 3288 3289 3290 3291
		if (signal_pending(current))
			break;

		if (need_resched())
			pktgen_resched(pkt_dev);
		else
			cpu_relax();
	}
3292
	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
3293 3294
}

Stephen Hemminger's avatar
Stephen Hemminger committed
3295
static void pktgen_xmit(struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
3296
{
3297
	unsigned int burst = READ_ONCE(pkt_dev->burst);
3298
	struct net_device *odev = pkt_dev->odev;
3299
	struct netdev_queue *txq;
3300
	struct sk_buff *skb;
Linus Torvalds's avatar
Linus Torvalds committed
3301 3302
	int ret;

3303 3304 3305 3306
	/* If device is offline, then don't send */
	if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) {
		pktgen_stop_device(pkt_dev);
		return;
3307 3308
	}

3309 3310 3311 3312
	/* This is max DELAY, this has special meaning of
	 * "never transmit"
	 */
	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
3313
		pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX);
3314
		return;
Linus Torvalds's avatar
Linus Torvalds committed
3315
	}
Luiz Capitulino's avatar
Luiz Capitulino committed
3316

3317
	/* If no skb or clone count exhausted then get new one */
3318 3319 3320 3321 3322 3323 3324
	if (!pkt_dev->skb || (pkt_dev->last_ok &&
			      ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
		/* build a new pkt */
		kfree_skb(pkt_dev->skb);

		pkt_dev->skb = fill_packet(odev, pkt_dev);
		if (pkt_dev->skb == NULL) {
3325
			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
3326 3327 3328
			schedule();
			pkt_dev->clone_count--;	/* back out increment, OOM */
			return;
Linus Torvalds's avatar
Linus Torvalds committed
3329
		}
3330
		pkt_dev->last_pkt_size = pkt_dev->skb->len;
3331
		pkt_dev->clone_count = 0;	/* reset counter */
Linus Torvalds's avatar
Linus Torvalds committed
3332
	}
3333

3334 3335 3336
	if (pkt_dev->delay && pkt_dev->last_ok)
		spin(pkt_dev, pkt_dev->next_tx);

3337 3338 3339
	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) {
		skb = pkt_dev->skb;
		skb->protocol = eth_type_trans(skb, skb->dev);
3340
		refcount_add(burst, &skb->users);
3341 3342 3343 3344 3345 3346 3347
		local_bh_disable();
		do {
			ret = netif_receive_skb(skb);
			if (ret == NET_RX_DROP)
				pkt_dev->errors++;
			pkt_dev->sofar++;
			pkt_dev->seq_num++;
3348
			if (refcount_read(&skb->users) != burst) {
3349 3350 3351
				/* skb was queued by rps/rfs or taps,
				 * so cannot reuse this skb
				 */
3352
				WARN_ON(refcount_sub_and_test(burst - 1, &skb->users));
3353 3354 3355 3356 3357 3358 3359 3360
				/* get out of the loop and wait
				 * until skb is consumed
				 */
				break;
			}
			/* skb was 'freed' by stack, so clean few
			 * bits and reuse it
			 */
3361
			skb_reset_tc(skb);
3362 3363
		} while (--burst > 0);
		goto out; /* Skips xmit_mode M_START_XMIT */
3364 3365
	} else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) {
		local_bh_disable();
3366
		refcount_inc(&pkt_dev->skb->users);
3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393

		ret = dev_queue_xmit(pkt_dev->skb);
		switch (ret) {
		case NET_XMIT_SUCCESS:
			pkt_dev->sofar++;
			pkt_dev->seq_num++;
			pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
			break;
		case NET_XMIT_DROP:
		case NET_XMIT_CN:
		/* These are all valid return codes for a qdisc but
		 * indicate packets are being dropped or will likely
		 * be dropped soon.
		 */
		case NETDEV_TX_BUSY:
		/* qdisc may call dev_hard_start_xmit directly in cases
		 * where no queues exist e.g. loopback device, virtual
		 * devices, etc. In this case we need to handle
		 * NETDEV_TX_ codes.
		 */
		default:
			pkt_dev->errors++;
			net_info_ratelimited("%s xmit error: %d\n",
					     pkt_dev->odevname, ret);
			break;
		}
		goto out;
3394 3395
	}

3396
	txq = skb_get_tx_queue(odev, pkt_dev->skb);
3397

3398 3399 3400
	local_bh_disable();

	HARD_TX_LOCK(odev, txq, smp_processor_id());
3401

3402
	if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) {
3403
		ret = NETDEV_TX_BUSY;
3404 3405 3406
		pkt_dev->last_ok = 0;
		goto unlock;
	}
3407
	refcount_add(burst, &pkt_dev->skb->users);
3408 3409 3410

xmit_more:
	ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0);
3411 3412 3413 3414 3415 3416

	switch (ret) {
	case NETDEV_TX_OK:
		pkt_dev->last_ok = 1;
		pkt_dev->sofar++;
		pkt_dev->seq_num++;
3417
		pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
3418 3419
		if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq))
			goto xmit_more;
3420
		break;
3421 3422 3423 3424 3425
	case NET_XMIT_DROP:
	case NET_XMIT_CN:
		/* skb has been consumed */
		pkt_dev->errors++;
		break;
3426
	default: /* Drivers are not supposed to return other values! */
3427 3428
		net_info_ratelimited("%s xmit error: %d\n",
				     pkt_dev->odevname, ret);
3429 3430 3431 3432
		pkt_dev->errors++;
		/* fallthru */
	case NETDEV_TX_BUSY:
		/* Retry it next time */
3433
		refcount_dec(&(pkt_dev->skb->users));
3434
		pkt_dev->last_ok = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
3435
	}
3436
	if (unlikely(burst))
3437
		WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users));
3438
unlock:
3439 3440
	HARD_TX_UNLOCK(odev, txq);

3441
out:
3442
	local_bh_enable();
Luiz Capitulino's avatar
Luiz Capitulino committed
3443

Linus Torvalds's avatar
Linus Torvalds committed
3444 3445
	/* If pkt_dev->count is zero, then run forever */
	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
3446
		pktgen_wait_for_skb(pkt_dev);
Luiz Capitulino's avatar
Luiz Capitulino committed
3447

Linus Torvalds's avatar
Linus Torvalds committed
3448 3449
		/* Done with this */
		pktgen_stop_device(pkt_dev);
Luiz Capitulino's avatar
Luiz Capitulino committed
3450 3451
	}
}
Linus Torvalds's avatar
Linus Torvalds committed
3452

3453
/*
Linus Torvalds's avatar
Linus Torvalds committed
3454 3455 3456
 * Main loop of the thread goes here
 */

3457
static int pktgen_thread_worker(void *arg)
Linus Torvalds's avatar
Linus Torvalds committed
3458 3459
{
	DEFINE_WAIT(wait);
3460
	struct pktgen_thread *t = arg;
Luiz Capitulino's avatar
Luiz Capitulino committed
3461
	struct pktgen_dev *pkt_dev = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
3462 3463
	int cpu = t->cpu;

3464
	BUG_ON(smp_processor_id() != cpu);
Linus Torvalds's avatar
Linus Torvalds committed
3465 3466

	init_waitqueue_head(&t->queue);
3467
	complete(&t->start_done);
Linus Torvalds's avatar
Linus Torvalds committed
3468

3469
	pr_debug("starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
Linus Torvalds's avatar
Linus Torvalds committed
3470

3471 3472
	set_freezable();

3473 3474
	while (!kthread_should_stop()) {
		pkt_dev = next_to_run(t);
Linus Torvalds's avatar
Linus Torvalds committed
3475

3476
		if (unlikely(!pkt_dev && t->control == 0)) {
Cong Wang's avatar
Cong Wang committed
3477
			if (t->net->pktgen_exiting)
3478
				break;
3479 3480 3481
			wait_event_interruptible_timeout(t->queue,
							 t->control != 0,
							 HZ/10);
3482
			try_to_freeze();
3483
			continue;
3484
		}
Linus Torvalds's avatar
Linus Torvalds committed
3485

3486
		if (likely(pkt_dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
3487 3488
			pktgen_xmit(pkt_dev);

3489 3490 3491 3492 3493 3494
			if (need_resched())
				pktgen_resched(pkt_dev);
			else
				cpu_relax();
		}

Luiz Capitulino's avatar
Luiz Capitulino committed
3495
		if (t->control & T_STOP) {
Linus Torvalds's avatar
Linus Torvalds committed
3496 3497 3498 3499
			pktgen_stop(t);
			t->control &= ~(T_STOP);
		}

Luiz Capitulino's avatar
Luiz Capitulino committed
3500
		if (t->control & T_RUN) {
Linus Torvalds's avatar
Linus Torvalds committed
3501 3502 3503 3504
			pktgen_run(t);
			t->control &= ~(T_RUN);
		}

Luiz Capitulino's avatar
Luiz Capitulino committed
3505
		if (t->control & T_REMDEVALL) {
Linus Torvalds's avatar
Linus Torvalds committed
3506
			pktgen_rem_all_ifs(t);
3507 3508 3509
			t->control &= ~(T_REMDEVALL);
		}

Luiz Capitulino's avatar
Luiz Capitulino committed
3510
		if (t->control & T_REMDEV) {
3511
			pktgen_rem_one_if(t);
Linus Torvalds's avatar
Linus Torvalds committed
3512 3513 3514
			t->control &= ~(T_REMDEV);
		}

3515
		try_to_freeze();
Luiz Capitulino's avatar
Luiz Capitulino committed
3516
	}
Linus Torvalds's avatar
Linus Torvalds committed
3517

3518
	pr_debug("%s stopping all device\n", t->tsk->comm);
Luiz Capitulino's avatar
Luiz Capitulino committed
3519
	pktgen_stop(t);
Linus Torvalds's avatar
Linus Torvalds committed
3520

3521
	pr_debug("%s removing all device\n", t->tsk->comm);
Luiz Capitulino's avatar
Luiz Capitulino committed
3522
	pktgen_rem_all_ifs(t);
Linus Torvalds's avatar
Linus Torvalds committed
3523

3524
	pr_debug("%s removing thread\n", t->tsk->comm);
Luiz Capitulino's avatar
Luiz Capitulino committed
3525
	pktgen_rem_thread(t);
3526

3527
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3528 3529
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3530
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
3531
					  const char *ifname, bool exact)
Linus Torvalds's avatar
Linus Torvalds committed
3532
{
3533
	struct pktgen_dev *p, *pkt_dev = NULL;
3534
	size_t len = strlen(ifname);
Luiz Capitulino's avatar
Luiz Capitulino committed
3535

3536 3537
	rcu_read_lock();
	list_for_each_entry_rcu(p, &t->if_list, list)
3538 3539 3540 3541 3542
		if (strncmp(p->odevname, ifname, len) == 0) {
			if (p->odevname[len]) {
				if (exact || p->odevname[len] != '@')
					continue;
			}
3543
			pkt_dev = p;
Luiz Capitulino's avatar
Luiz Capitulino committed
3544 3545 3546
			break;
		}

3547
	rcu_read_unlock();
3548
	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
Luiz Capitulino's avatar
Luiz Capitulino committed
3549
	return pkt_dev;
Linus Torvalds's avatar
Linus Torvalds committed
3550 3551
}

3552 3553
/*
 * Adds a dev at front of if_list.
Linus Torvalds's avatar
Linus Torvalds committed
3554 3555
 */

Luiz Capitulino's avatar
Luiz Capitulino committed
3556 3557
static int add_dev_to_thread(struct pktgen_thread *t,
			     struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
3558 3559
{
	int rv = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
3560

3561 3562 3563 3564 3565 3566
	/* This function cannot be called concurrently, as its called
	 * under pktgen_thread_lock mutex, but it can run from
	 * userspace on another CPU than the kthread.  The if_lock()
	 * is used here to sync with concurrent instances of
	 * _rem_dev_from_if_list() invoked via kthread, which is also
	 * updating the if_list */
Luiz Capitulino's avatar
Luiz Capitulino committed
3567 3568 3569
	if_lock(t);

	if (pkt_dev->pg_thread) {
3570
		pr_err("ERROR: already assigned to a thread\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
3571 3572 3573
		rv = -EBUSY;
		goto out;
	}
3574

Linus Torvalds's avatar
Linus Torvalds committed
3575
	pkt_dev->running = 0;
3576 3577
	pkt_dev->pg_thread = t;
	list_add_rcu(&pkt_dev->list, &t->if_list);
Linus Torvalds's avatar
Linus Torvalds committed
3578

Luiz Capitulino's avatar
Luiz Capitulino committed
3579 3580 3581
out:
	if_unlock(t);
	return rv;
Linus Torvalds's avatar
Linus Torvalds committed
3582 3583 3584 3585
}

/* Called under thread lock */

Luiz Capitulino's avatar
Luiz Capitulino committed
3586
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
Linus Torvalds's avatar
Linus Torvalds committed
3587
{
Luiz Capitulino's avatar
Luiz Capitulino committed
3588
	struct pktgen_dev *pkt_dev;
3589
	int err;
Eric Dumazet's avatar
Eric Dumazet committed
3590
	int node = cpu_to_node(t->cpu);
Luiz Capitulino's avatar
Luiz Capitulino committed
3591

Linus Torvalds's avatar
Linus Torvalds committed
3592 3593
	/* We don't allow a device to be on several threads */

Cong Wang's avatar
Cong Wang committed
3594
	pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND);
3595
	if (pkt_dev) {
3596
		pr_err("ERROR: interface already used\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
3597 3598
		return -EBUSY;
	}
3599

Eric Dumazet's avatar
Eric Dumazet committed
3600
	pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node);
3601 3602 3603
	if (!pkt_dev)
		return -ENOMEM;

3604
	strcpy(pkt_dev->odevname, ifname);
3605
	pkt_dev->flows = vzalloc_node(MAX_CFLOWS * sizeof(struct flow_state),
Eric Dumazet's avatar
Eric Dumazet committed
3606
				      node);
3607 3608 3609 3610 3611
	if (pkt_dev->flows == NULL) {
		kfree(pkt_dev);
		return -ENOMEM;
	}

3612
	pkt_dev->removal_mark = 0;
3613
	pkt_dev->nfrags = 0;
3614
	pkt_dev->delay = pg_delay_d;
3615 3616
	pkt_dev->count = pg_count_d;
	pkt_dev->sofar = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
3617
	pkt_dev->udp_src_min = 9;	/* sink port */
3618 3619 3620
	pkt_dev->udp_src_max = 9;
	pkt_dev->udp_dst_min = 9;
	pkt_dev->udp_dst_max = 9;
Francesco Fondelli's avatar
Francesco Fondelli committed
3621 3622 3623 3624 3625 3626
	pkt_dev->vlan_p = 0;
	pkt_dev->vlan_cfi = 0;
	pkt_dev->vlan_id = 0xffff;
	pkt_dev->svlan_p = 0;
	pkt_dev->svlan_cfi = 0;
	pkt_dev->svlan_id = 0xffff;
3627
	pkt_dev->burst = 1;
Robert Olsson's avatar
Robert Olsson committed
3628
	pkt_dev->node = -1;
Francesco Fondelli's avatar
Francesco Fondelli committed
3629

Cong Wang's avatar
Cong Wang committed
3630
	err = pktgen_setup_dev(t->net, pkt_dev, ifname);
3631 3632
	if (err)
		goto out1;
3633 3634
	if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
		pkt_dev->clone_skb = pg_clone_skb_d;
3635

Cong Wang's avatar
Cong Wang committed
3636
	pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir,
3637
					  &pktgen_if_fops, pkt_dev);
3638
	if (!pkt_dev->entry) {
3639
		pr_err("cannot create %s/%s procfs entry\n",
3640
		       PG_PROC_DIR, ifname);
3641 3642
		err = -EINVAL;
		goto out2;
3643
	}
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
3644 3645 3646
#ifdef CONFIG_XFRM
	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
	pkt_dev->ipsproto = IPPROTO_ESP;
3647 3648 3649 3650 3651 3652 3653

	/* xfrm tunnel mode needs additional dst to extract outter
	 * ip header protocol/ttl/id field, here creat a phony one.
	 * instead of looking for a valid rt, which definitely hurting
	 * performance under such circumstance.
	 */
	pkt_dev->dstops.family = AF_INET;
3654 3655 3656 3657
	pkt_dev->xdst.u.dst.dev = pkt_dev->odev;
	dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false);
	pkt_dev->xdst.child = &pkt_dev->xdst.u.dst;
	pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
3658
#endif
3659 3660

	return add_dev_to_thread(t, pkt_dev);
3661 3662 3663
out2:
	dev_put(pkt_dev->odev);
out1:
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
3664 3665 3666
#ifdef CONFIG_XFRM
	free_SAs(pkt_dev);
#endif
3667
	vfree(pkt_dev->flows);
3668 3669
	kfree(pkt_dev);
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
3670 3671
}

Cong Wang's avatar
Cong Wang committed
3672
static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
Linus Torvalds's avatar
Linus Torvalds committed
3673
{
3674
	struct pktgen_thread *t;
3675
	struct proc_dir_entry *pe;
3676
	struct task_struct *p;
Luiz Capitulino's avatar
Luiz Capitulino committed
3677

Eric Dumazet's avatar
Eric Dumazet committed
3678 3679
	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
			 cpu_to_node(cpu));
Luiz Capitulino's avatar
Luiz Capitulino committed
3680
	if (!t) {
3681
		pr_err("ERROR: out of memory, can't create new thread\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
3682 3683 3684
		return -ENOMEM;
	}

3685
	mutex_init(&t->if_lock);
Linus Torvalds's avatar
Linus Torvalds committed
3686
	t->cpu = cpu;
Luiz Capitulino's avatar
Luiz Capitulino committed
3687

3688 3689
	INIT_LIST_HEAD(&t->if_list);

Cong Wang's avatar
Cong Wang committed
3690
	list_add_tail(&t->th_list, &pn->pktgen_threads);
3691
	init_completion(&t->start_done);
3692

3693 3694 3695 3696
	p = kthread_create_on_node(pktgen_thread_worker,
				   t,
				   cpu_to_node(cpu),
				   "kpktgend_%d", cpu);
3697
	if (IS_ERR(p)) {
3698
		pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
3699 3700 3701 3702 3703 3704 3705
		list_del(&t->th_list);
		kfree(t);
		return PTR_ERR(p);
	}
	kthread_bind(p, cpu);
	t->tsk = p;

Cong Wang's avatar
Cong Wang committed
3706
	pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir,
3707
			      &pktgen_thread_fops, t);
Luiz Capitulino's avatar
Luiz Capitulino committed
3708
	if (!pe) {
3709
		pr_err("cannot create %s/%s procfs entry\n",
3710 3711 3712
		       PG_PROC_DIR, t->tsk->comm);
		kthread_stop(p);
		list_del(&t->th_list);
Luiz Capitulino's avatar
Luiz Capitulino committed
3713 3714 3715
		kfree(t);
		return -EINVAL;
	}
3716

Cong Wang's avatar
Cong Wang committed
3717
	t->net = pn;
3718
	get_task_struct(p);
3719
	wake_up_process(p);
3720
	wait_for_completion(&t->start_done);
Linus Torvalds's avatar
Linus Torvalds committed
3721 3722 3723 3724

	return 0;
}

3725 3726
/*
 * Removes a device from the thread if_list.
Linus Torvalds's avatar
Linus Torvalds committed
3727
 */
Luiz Capitulino's avatar
Luiz Capitulino committed
3728 3729
static void _rem_dev_from_if_list(struct pktgen_thread *t,
				  struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
3730
{
3731 3732
	struct list_head *q, *n;
	struct pktgen_dev *p;
Linus Torvalds's avatar
Linus Torvalds committed
3733

3734
	if_lock(t);
3735 3736 3737
	list_for_each_safe(q, n, &t->if_list) {
		p = list_entry(q, struct pktgen_dev, list);
		if (p == pkt_dev)
3738
			list_del_rcu(&p->list);
Linus Torvalds's avatar
Linus Torvalds committed
3739
	}
3740
	if_unlock(t);
Linus Torvalds's avatar
Linus Torvalds committed
3741 3742
}

Luiz Capitulino's avatar
Luiz Capitulino committed
3743 3744
static int pktgen_remove_device(struct pktgen_thread *t,
				struct pktgen_dev *pkt_dev)
Linus Torvalds's avatar
Linus Torvalds committed
3745
{
3746
	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
Linus Torvalds's avatar
Linus Torvalds committed
3747

Luiz Capitulino's avatar
Luiz Capitulino committed
3748
	if (pkt_dev->running) {
3749
		pr_warn("WARNING: trying to remove a running interface, stopping it now\n");
Luiz Capitulino's avatar
Luiz Capitulino committed
3750 3751 3752 3753
		pktgen_stop_device(pkt_dev);
	}

	/* Dis-associate from the interface */
Linus Torvalds's avatar
Linus Torvalds committed
3754 3755 3756

	if (pkt_dev->odev) {
		dev_put(pkt_dev->odev);
Luiz Capitulino's avatar
Luiz Capitulino committed
3757 3758 3759
		pkt_dev->odev = NULL;
	}

3760 3761 3762
	/* Remove proc before if_list entry, because add_device uses
	 * list to determine if interface already exist, avoid race
	 * with proc_create_data() */
3763
	proc_remove(pkt_dev->entry);
Linus Torvalds's avatar
Linus Torvalds committed
3764

3765 3766 3767
	/* And update the thread if_list */
	_rem_dev_from_if_list(t, pkt_dev);

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
3768 3769 3770
#ifdef CONFIG_XFRM
	free_SAs(pkt_dev);
#endif
3771
	vfree(pkt_dev->flows);
3772 3773
	if (pkt_dev->page)
		put_page(pkt_dev->page);
3774
	kfree_rcu(pkt_dev, rcu);
Luiz Capitulino's avatar
Luiz Capitulino committed
3775
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3776 3777
}

Cong Wang's avatar
Cong Wang committed
3778
static int __net_init pg_net_init(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
3779
{
Cong Wang's avatar
Cong Wang committed
3780
	struct pktgen_net *pn = net_generic(net, pg_net_id);
3781
	struct proc_dir_entry *pe;
Cong Wang's avatar
Cong Wang committed
3782 3783 3784 3785 3786 3787 3788 3789
	int cpu, ret = 0;

	pn->net = net;
	INIT_LIST_HEAD(&pn->pktgen_threads);
	pn->pktgen_exiting = false;
	pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net);
	if (!pn->proc_dir) {
		pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR);
3790
		return -ENODEV;
Cong Wang's avatar
Cong Wang committed
3791 3792
	}
	pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops);
Luiz Capitulino's avatar
Luiz Capitulino committed
3793
	if (pe == NULL) {
Cong Wang's avatar
Cong Wang committed
3794
		pr_err("cannot create %s procfs entry\n", PGCTRL);
WANG Cong's avatar
WANG Cong committed
3795
		ret = -EINVAL;
Cong Wang's avatar
Cong Wang committed
3796
		goto remove;
Luiz Capitulino's avatar
Luiz Capitulino committed
3797
	}
Linus Torvalds's avatar
Linus Torvalds committed
3798

3799
	for_each_online_cpu(cpu) {
3800
		int err;
Linus Torvalds's avatar
Linus Torvalds committed
3801

Cong Wang's avatar
Cong Wang committed
3802
		err = pktgen_create_thread(cpu, pn);
3803
		if (err)
Cong Wang's avatar
Cong Wang committed
3804
			pr_warn("Cannot create thread for cpu %d (%d)\n",
3805
				   cpu, err);
Luiz Capitulino's avatar
Luiz Capitulino committed
3806
	}
3807

Cong Wang's avatar
Cong Wang committed
3808 3809
	if (list_empty(&pn->pktgen_threads)) {
		pr_err("Initialization failed for all threads\n");
WANG Cong's avatar
WANG Cong committed
3810
		ret = -ENODEV;
Cong Wang's avatar
Cong Wang committed
3811
		goto remove_entry;
3812 3813
	}

Luiz Capitulino's avatar
Luiz Capitulino committed
3814
	return 0;
WANG Cong's avatar
WANG Cong committed
3815

Cong Wang's avatar
Cong Wang committed
3816 3817 3818
remove_entry:
	remove_proc_entry(PGCTRL, pn->proc_dir);
remove:
3819
	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
WANG Cong's avatar
WANG Cong committed
3820
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
3821 3822
}

Cong Wang's avatar
Cong Wang committed
3823
static void __net_exit pg_net_exit(struct net *net)
Linus Torvalds's avatar
Linus Torvalds committed
3824
{
Cong Wang's avatar
Cong Wang committed
3825
	struct pktgen_net *pn = net_generic(net, pg_net_id);
3826 3827
	struct pktgen_thread *t;
	struct list_head *q, *n;
3828
	LIST_HEAD(list);
Linus Torvalds's avatar
Linus Torvalds committed
3829

Luiz Capitulino's avatar
Luiz Capitulino committed
3830
	/* Stop all interfaces & threads */
Cong Wang's avatar
Cong Wang committed
3831
	pn->pktgen_exiting = true;
Linus Torvalds's avatar
Linus Torvalds committed
3832

3833
	mutex_lock(&pktgen_thread_lock);
Cong Wang's avatar
Cong Wang committed
3834
	list_splice_init(&pn->pktgen_threads, &list);
3835 3836 3837
	mutex_unlock(&pktgen_thread_lock);

	list_for_each_safe(q, n, &list) {
3838
		t = list_entry(q, struct pktgen_thread, th_list);
3839
		list_del(&t->th_list);
3840
		kthread_stop(t->tsk);
3841
		put_task_struct(t->tsk);
3842
		kfree(t);
Luiz Capitulino's avatar
Luiz Capitulino committed
3843
	}
Linus Torvalds's avatar
Linus Torvalds committed
3844

Cong Wang's avatar
Cong Wang committed
3845
	remove_proc_entry(PGCTRL, pn->proc_dir);
3846
	remove_proc_entry(PG_PROC_DIR, pn->net->proc_net);
Cong Wang's avatar
Cong Wang committed
3847 3848 3849 3850 3851 3852 3853
}

static struct pernet_operations pg_net_ops = {
	.init = pg_net_init,
	.exit = pg_net_exit,
	.id   = &pg_net_id,
	.size = sizeof(struct pktgen_net),
Kirill Tkhai's avatar
Kirill Tkhai committed
3854
	.async = true,
Cong Wang's avatar
Cong Wang committed
3855 3856 3857 3858 3859
};

static int __init pg_init(void)
{
	int ret = 0;
Linus Torvalds's avatar
Linus Torvalds committed
3860

Cong Wang's avatar
Cong Wang committed
3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875
	pr_info("%s", version);
	ret = register_pernet_subsys(&pg_net_ops);
	if (ret)
		return ret;
	ret = register_netdevice_notifier(&pktgen_notifier_block);
	if (ret)
		unregister_pernet_subsys(&pg_net_ops);

	return ret;
}

static void __exit pg_cleanup(void)
{
	unregister_netdevice_notifier(&pktgen_notifier_block);
	unregister_pernet_subsys(&pg_net_ops);
3876
	/* Don't need rcu_barrier() due to use of kfree_rcu() */
Linus Torvalds's avatar
Linus Torvalds committed
3877 3878 3879 3880 3881
}

module_init(pg_init);
module_exit(pg_cleanup);

Stephen Hemminger's avatar
Stephen Hemminger committed
3882
MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
Linus Torvalds's avatar
Linus Torvalds committed
3883 3884
MODULE_DESCRIPTION("Packet Generator tool");
MODULE_LICENSE("GPL");
Stephen Hemminger's avatar
Stephen Hemminger committed
3885
MODULE_VERSION(VERSION);
Linus Torvalds's avatar
Linus Torvalds committed
3886
module_param(pg_count_d, int, 0);
Stephen Hemminger's avatar
Stephen Hemminger committed
3887
MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
Linus Torvalds's avatar
Linus Torvalds committed
3888
module_param(pg_delay_d, int, 0);
Stephen Hemminger's avatar
Stephen Hemminger committed
3889
MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
Linus Torvalds's avatar
Linus Torvalds committed
3890
module_param(pg_clone_skb_d, int, 0);
Stephen Hemminger's avatar
Stephen Hemminger committed
3891
MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
Linus Torvalds's avatar
Linus Torvalds committed
3892
module_param(debug, int, 0);
Stephen Hemminger's avatar
Stephen Hemminger committed
3893
MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");