pktgen.c 91.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * 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>
 * Jens Ls <jens.laas@data.slu.se>
 *
 * 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
L
Linus Torvalds 已提交
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
L
Linus Torvalds 已提交
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
L
Linus Torvalds 已提交
52 53
 * clones.
 *
54
 * Also moved to /proc/net/pktgen/
L
Linus Torvalds 已提交
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
 *
L
Linus Torvalds 已提交
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
L
Linus Torvalds 已提交
72 73 74
 * way. The if_lock should be possible to remove when add/rem_device is merged
 * into this too.
 *
75 76
 * By design there should only be *one* "controlling" process. In practice
 * multiple write accesses gives unpredictable result. Understood by "write"
L
Linus Torvalds 已提交
77
 * to /proc gives result code thats should be read be the "writer".
78
 * For practical use this should be no problem.
L
Linus Torvalds 已提交
79
 *
80 81
 * 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.
L
Linus Torvalds 已提交
82 83
 * --ro
 *
84
 * Fix refcount off by one if first packet fails, potential null deref,
L
Linus Torvalds 已提交
85 86 87 88 89 90 91
 * 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>
92
 *
L
Linus Torvalds 已提交
93 94 95
 * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
 * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
 *
96
 * New xmit() return, do_div and misc clean up by Stephen Hemminger
L
Linus Torvalds 已提交
97 98
 * <shemminger@osdl.org> 040923
 *
99
 * Randy Dunlap fixed u64 printk compiler waring
L
Linus Torvalds 已提交
100 101 102 103
 *
 * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
 * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
 *
104
 * Corrections from Nikolai Malykh (nmalykh@bilim.com)
L
Linus Torvalds 已提交
105 106
 * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
 *
107
 * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
L
Linus Torvalds 已提交
108
 * 050103
109 110 111
 *
 * MPLS support by Steven Whitehouse <steve@chygwyn.com>
 *
F
Francesco Fondelli 已提交
112 113
 * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
 *
A
Adit Ranadive 已提交
114 115 116
 * Fixed src_mac command to set source mac of packet to value specified in
 * command by Adit Ranadive <adit.262@gmail.com>
 *
L
Linus Torvalds 已提交
117 118 119 120 121 122
 */
#include <linux/sys.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
123
#include <linux/mutex.h>
L
Linus Torvalds 已提交
124 125 126 127 128 129 130 131 132
#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>
133
#include <linux/capability.h>
A
Andrew Morton 已提交
134
#include <linux/freezer.h>
L
Linus Torvalds 已提交
135 136
#include <linux/delay.h>
#include <linux/timer.h>
137
#include <linux/list.h>
L
Linus Torvalds 已提交
138 139 140 141 142 143 144
#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>
F
Francesco Fondelli 已提交
145
#include <linux/if_vlan.h>
L
Linus Torvalds 已提交
146 147 148 149 150
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/proc_fs.h>
151
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
152
#include <linux/wait.h>
153
#include <linux/etherdevice.h>
154
#include <linux/kthread.h>
L
Linus Torvalds 已提交
155 156 157
#include <net/checksum.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
J
Jamal Hadi Salim 已提交
158 159 160
#ifdef CONFIG_XFRM
#include <net/xfrm.h>
#endif
L
Linus Torvalds 已提交
161 162 163 164 165 166
#include <asm/byteorder.h>
#include <linux/rcupdate.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
L
Luiz Capitulino 已提交
167
#include <asm/div64.h>		/* do_div */
L
Linus Torvalds 已提交
168 169
#include <asm/timex.h>

F
Francesco Fondelli 已提交
170
#define VERSION  "pktgen v2.68: Packet Generator for packet performance testing.\n"
L
Linus Torvalds 已提交
171 172 173 174

/* The buckets are exponential in 'width' */
#define LAT_BUCKETS_MAX 32
#define IP_NAME_SZ 32
175
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
176
#define MPLS_STACK_BOTTOM htonl(0x00000100)
L
Linus Torvalds 已提交
177 178

/* Device flag bits */
L
Luiz Capitulino 已提交
179 180 181 182 183 184 185 186
#define F_IPSRC_RND   (1<<0)	/* IP-Src Random  */
#define F_IPDST_RND   (1<<1)	/* IP-Dst Random  */
#define F_UDPSRC_RND  (1<<2)	/* UDP-Src Random */
#define F_UDPDST_RND  (1<<3)	/* UDP-Dst Random */
#define F_MACSRC_RND  (1<<4)	/* MAC-Src Random */
#define F_MACDST_RND  (1<<5)	/* MAC-Dst Random */
#define F_TXSIZE_RND  (1<<6)	/* Transmit size is random */
#define F_IPV6        (1<<7)	/* Interface in IPV6 Mode */
187
#define F_MPLS_RND    (1<<8)	/* Random MPLS labels */
F
Francesco Fondelli 已提交
188 189
#define F_VID_RND     (1<<9)	/* Random VLAN ID */
#define F_SVID_RND    (1<<10)	/* Random SVLAN ID */
190
#define F_FLOW_SEQ    (1<<11)	/* Sequential flows */
J
Jamal Hadi Salim 已提交
191
#define F_IPSEC_ON    (1<<12)	/* ipsec on for flows */
L
Linus Torvalds 已提交
192 193

/* Thread control flag bits */
L
Luiz Capitulino 已提交
194 195 196 197 198
#define T_TERMINATE   (1<<0)
#define T_STOP        (1<<1)	/* Stop run */
#define T_RUN         (1<<2)	/* Start run */
#define T_REMDEVALL   (1<<3)	/* Remove all devs */
#define T_REMDEV      (1<<4)	/* Remove one dev */
L
Linus Torvalds 已提交
199 200 201 202 203 204 205

/* If lock -- can be removed after some work */
#define   if_lock(t)           spin_lock(&(t->if_lock));
#define   if_unlock(t)           spin_unlock(&(t->if_lock));

/* Used to help with determining the pkts on receive */
#define PKTGEN_MAGIC 0xbe9be955
206 207 208
#define PG_PROC_DIR "pktgen"
#define PGCTRL	    "pgctrl"
static struct proc_dir_entry *pg_proc_dir = NULL;
L
Linus Torvalds 已提交
209 210 211

#define MAX_CFLOWS  65536

F
Francesco Fondelli 已提交
212 213 214
#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)

L
Luiz Capitulino 已提交
215
struct flow_state {
A
Al Viro 已提交
216
	__be32 cur_daddr;
L
Luiz Capitulino 已提交
217
	int count;
J
Jamal Hadi Salim 已提交
218 219 220
#ifdef CONFIG_XFRM
	struct xfrm_state *x;
#endif
221
	__u32 flags;
L
Linus Torvalds 已提交
222 223
};

224 225 226
/* flow flag bits */
#define F_INIT   (1<<0)		/* flow has been initialized */

L
Linus Torvalds 已提交
227 228 229 230
struct pktgen_dev {
	/*
	 * Try to keep frequent/infrequent used vars. separated.
	 */
231 232
	struct proc_dir_entry *entry;	/* proc file */
	struct pktgen_thread *pg_thread;/* the owner */
233
	struct list_head list;		/* Used for chaining in the thread's run-queue */
L
Linus Torvalds 已提交
234

L
Luiz Capitulino 已提交
235
	int running;		/* if this changes to false, the test will stop */
L
Linus Torvalds 已提交
236

L
Luiz Capitulino 已提交
237 238 239 240
	/* If min != max, then we will either do a linear iteration, or
	 * we will do a random selection from within the range.
	 */
	__u32 flags;
241 242
	int removal_mark;	/* non-zero => the device is marked for
				 * removal by worker thread */
L
Linus Torvalds 已提交
243

L
Luiz Capitulino 已提交
244 245
	int min_pkt_size;	/* = ETH_ZLEN; */
	int max_pkt_size;	/* = ETH_ZLEN; */
246
	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
L
Luiz Capitulino 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	int nfrags;
	__u32 delay_us;		/* Default delay */
	__u32 delay_ns;
	__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 */
	__u64 errors;		/* Errors when trying to transmit, pkts will be re-sent */

	/* runtime counters relating to clone_skb */
	__u64 next_tx_us;	/* timestamp of when to tx next */
	__u32 next_tx_ns;

	__u64 allocated_skbs;
	__u32 clone_count;
	int last_ok;		/* Was last skb sent?
				 * Or a failed transmit of some sort?  This will keep
				 * sequence numbers in order, for example.
				 */
	__u64 started_at;	/* micro-seconds */
	__u64 stopped_at;	/* micro-seconds */
	__u64 idle_acc;		/* micro-seconds */
	__u32 seq_num;

	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.
				 * For instance, if you want to send 1024 identical packets
				 * before creating a new packet, set clone_skb to 1024.
				 */

	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;
L
Linus Torvalds 已提交
286
	/* For ranges */
L
Luiz Capitulino 已提交
287 288 289 290 291 292 293 294
	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.
	 */
A
Al Viro 已提交
295 296 297 298
	__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 */
L
Luiz Capitulino 已提交
299 300 301 302 303 304

	__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 */

F
Francesco Fondelli 已提交
305 306 307 308
	/* DSCP + ECN */
	__u8 tos;            /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */
	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */

309 310 311 312
	/* MPLS */
	unsigned nr_labels;	/* Depth of stack, 0 = no MPLS */
	__be32 labels[MAX_MPLS_LABELS];

F
Francesco Fondelli 已提交
313 314 315 316 317 318 319 320 321
	/* 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 */

L
Luiz Capitulino 已提交
322 323 324 325 326 327 328 329
	__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;
A
Al Viro 已提交
330 331
	__be32 cur_saddr;
	__be32 cur_daddr;
L
Luiz Capitulino 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	__u16 cur_udp_dst;
	__u16 cur_udp_src;
	__u32 cur_pkt_size;

	__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 */

	struct sk_buff *skb;	/* skb we are to transmit next, mainly used for when we
				 * are transmitting the same one multiple times
				 */
	struct net_device *odev;	/* The out-going device.  Note that the device should
					 * have it's pg_info pointer pointing back to this
					 * device.  This will be set when the user specifies
					 * the out-going device name (not when the inject is
					 * started as it used to do.)
					 */
L
Linus Torvalds 已提交
356
	struct flow_state *flows;
L
Luiz Capitulino 已提交
357 358 359
	unsigned cflows;	/* Concurrent flows (config) */
	unsigned lflow;		/* Flow length  (config) */
	unsigned nflows;	/* accumulated flows (stats) */
360
	unsigned curfl;		/* current sequenced flow (state)*/
J
Jamal Hadi Salim 已提交
361 362 363 364
#ifdef CONFIG_XFRM
	__u8	ipsmode;		/* IPSEC mode (config) */
	__u8	ipsproto;		/* IPSEC type (config) */
#endif
365
	char result[512];
L
Linus Torvalds 已提交
366 367 368
};

struct pktgen_hdr {
A
Al Viro 已提交
369 370 371 372
	__be32 pgh_magic;
	__be32 seq_num;
	__be32 tv_sec;
	__be32 tv_usec;
L
Linus Torvalds 已提交
373 374 375
};

struct pktgen_thread {
L
Luiz Capitulino 已提交
376
	spinlock_t if_lock;
377
	struct list_head if_list;	/* All device here */
378
	struct list_head th_list;
379
	struct task_struct *tsk;
L
Luiz Capitulino 已提交
380 381 382 383 384 385
	char result[512];
	u32 max_before_softirq;	/* We'll call do_softirq to prevent starvation. */

	/* Field for thread to receive "posted" events terminate, stop ifs etc. */

	u32 control;
L
Linus Torvalds 已提交
386 387
	int cpu;

L
Luiz Capitulino 已提交
388
	wait_queue_head_t queue;
L
Linus Torvalds 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
};

#define REMOVE 1
#define FIND   0

/*  This code works around the fact that do_div cannot handle two 64-bit
    numbers, and regular 64-bit division doesn't work on x86 kernels.
    --Ben
*/

#define PG_DIV 0

/* This was emailed to LMKL by: Chris Caputo <ccaputo@alt.net>
 * Function copied/adapted/optimized from:
 *
 *  nemesis.sourceforge.net/browse/lib/static/intmath/ix86/intmath.c.html
 *
 * Copyright 1994, University of Cambridge Computer Laboratory
 * All Rights Reserved.
 *
 */
410
static inline s64 divremdi3(s64 x, s64 y, int type)
L
Linus Torvalds 已提交
411
{
L
Luiz Capitulino 已提交
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
	u64 a = (x < 0) ? -x : x;
	u64 b = (y < 0) ? -y : y;
	u64 res = 0, d = 1;

	if (b > 0) {
		while (b < a) {
			b <<= 1;
			d <<= 1;
		}
	}

	do {
		if (a >= b) {
			a -= b;
			res += d;
		}
		b >>= 1;
		d >>= 1;
	}
	while (d);

	if (PG_DIV == type) {
		return (((x ^ y) & (1ll << 63)) == 0) ? res : -(s64) res;
	} else {
		return ((x & (1ll << 63)) == 0) ? a : -(s64) a;
	}
L
Linus Torvalds 已提交
438 439 440 441
}

/* End of hacks to deal with 64-bit math on x86 */

442
/** Convert to milliseconds */
L
Luiz Capitulino 已提交
443
static inline __u64 tv_to_ms(const struct timeval *tv)
L
Linus Torvalds 已提交
444
{
L
Luiz Capitulino 已提交
445 446 447
	__u64 ms = tv->tv_usec / 1000;
	ms += (__u64) tv->tv_sec * (__u64) 1000;
	return ms;
L
Linus Torvalds 已提交
448 449 450
}

/** Convert to micro-seconds */
L
Luiz Capitulino 已提交
451
static inline __u64 tv_to_us(const struct timeval *tv)
L
Linus Torvalds 已提交
452
{
L
Luiz Capitulino 已提交
453 454 455
	__u64 us = tv->tv_usec;
	us += (__u64) tv->tv_sec * (__u64) 1000000;
	return us;
L
Linus Torvalds 已提交
456 457
}

L
Luiz Capitulino 已提交
458 459 460 461 462 463 464
static inline __u64 pg_div(__u64 n, __u32 base)
{
	__u64 tmp = n;
	do_div(tmp, base);
	/* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
	   n, base, tmp); */
	return tmp;
L
Linus Torvalds 已提交
465 466
}

L
Luiz Capitulino 已提交
467
static inline __u64 pg_div64(__u64 n, __u64 base)
L
Linus Torvalds 已提交
468
{
L
Luiz Capitulino 已提交
469
	__u64 tmp = n;
L
Linus Torvalds 已提交
470
/*
471
 * How do we know if the architecture we are running on
L
Linus Torvalds 已提交
472
 * supports division with 64 bit base?
473
 *
L
Linus Torvalds 已提交
474
 */
L
Luiz Capitulino 已提交
475
#if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__)
L
Linus Torvalds 已提交
476

L
Luiz Capitulino 已提交
477
	do_div(tmp, base);
L
Linus Torvalds 已提交
478
#else
L
Luiz Capitulino 已提交
479
	tmp = divremdi3(n, base, PG_DIV);
L
Linus Torvalds 已提交
480
#endif
L
Luiz Capitulino 已提交
481
	return tmp;
L
Linus Torvalds 已提交
482 483
}

L
Luiz Capitulino 已提交
484
static inline __u64 getCurMs(void)
L
Linus Torvalds 已提交
485
{
L
Luiz Capitulino 已提交
486 487 488
	struct timeval tv;
	do_gettimeofday(&tv);
	return tv_to_ms(&tv);
L
Linus Torvalds 已提交
489 490
}

L
Luiz Capitulino 已提交
491
static inline __u64 getCurUs(void)
L
Linus Torvalds 已提交
492
{
L
Luiz Capitulino 已提交
493 494 495
	struct timeval tv;
	do_gettimeofday(&tv);
	return tv_to_us(&tv);
L
Linus Torvalds 已提交
496 497
}

L
Luiz Capitulino 已提交
498
static inline __u64 tv_diff(const struct timeval *a, const struct timeval *b)
L
Linus Torvalds 已提交
499
{
L
Luiz Capitulino 已提交
500
	return tv_to_us(a) - tv_to_us(b);
L
Linus Torvalds 已提交
501 502 503 504 505 506
}

/* old include end */

static char version[] __initdata = VERSION;

L
Luiz Capitulino 已提交
507 508 509 510
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,
					  const char *ifname);
L
Linus Torvalds 已提交
511 512 513 514
static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
static void pktgen_run_all_threads(void);
static void pktgen_stop_all_threads_ifs(void);
static int pktgen_stop_device(struct pktgen_dev *pkt_dev);
L
Luiz Capitulino 已提交
515
static void pktgen_stop(struct pktgen_thread *t);
L
Linus Torvalds 已提交
516
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
517

L
Luiz Capitulino 已提交
518 519
static unsigned int scan_ip6(const char *s, char ip[16]);
static unsigned int fmt_ip6(char *s, const char ip[16]);
L
Linus Torvalds 已提交
520 521

/* Module parameters, defaults. */
L
Luiz Capitulino 已提交
522
static int pg_count_d = 1000;	/* 1000 pkts by default */
523 524 525
static int pg_delay_d;
static int pg_clone_skb_d;
static int debug;
L
Linus Torvalds 已提交
526

527
static DEFINE_MUTEX(pktgen_thread_lock);
528
static LIST_HEAD(pktgen_threads);
L
Linus Torvalds 已提交
529 530 531 532 533 534

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

/*
535
 * /proc handling functions
L
Linus Torvalds 已提交
536 537 538
 *
 */

539
static int pgctrl_show(struct seq_file *seq, void *v)
L
Luiz Capitulino 已提交
540
{
541 542
	seq_puts(seq, VERSION);
	return 0;
L
Linus Torvalds 已提交
543 544
}

L
Luiz Capitulino 已提交
545 546
static ssize_t pgctrl_write(struct file *file, const char __user * buf,
			    size_t count, loff_t * ppos)
L
Linus Torvalds 已提交
547 548
{
	int err = 0;
549
	char data[128];
L
Linus Torvalds 已提交
550

L
Luiz Capitulino 已提交
551 552
	if (!capable(CAP_NET_ADMIN)) {
		err = -EPERM;
L
Linus Torvalds 已提交
553
		goto out;
L
Luiz Capitulino 已提交
554
	}
L
Linus Torvalds 已提交
555

556 557
	if (count > sizeof(data))
		count = sizeof(data);
L
Linus Torvalds 已提交
558 559

	if (copy_from_user(data, buf, count)) {
560
		err = -EFAULT;
561
		goto out;
L
Luiz Capitulino 已提交
562 563
	}
	data[count - 1] = 0;	/* Make string */
L
Linus Torvalds 已提交
564

L
Luiz Capitulino 已提交
565
	if (!strcmp(data, "stop"))
L
Linus Torvalds 已提交
566 567
		pktgen_stop_all_threads_ifs();

L
Luiz Capitulino 已提交
568
	else if (!strcmp(data, "start"))
L
Linus Torvalds 已提交
569 570
		pktgen_run_all_threads();

L
Luiz Capitulino 已提交
571
	else
572
		printk(KERN_WARNING "pktgen: Unknown command: %s\n", data);
L
Linus Torvalds 已提交
573 574 575

	err = count;

L
Luiz Capitulino 已提交
576 577
out:
	return err;
L
Linus Torvalds 已提交
578 579
}

580 581 582 583 584
static int pgctrl_open(struct inode *inode, struct file *file)
{
	return single_open(file, pgctrl_show, PDE(inode)->data);
}

585
static const struct file_operations pktgen_fops = {
L
Luiz Capitulino 已提交
586 587 588 589 590 591
	.owner   = THIS_MODULE,
	.open    = pgctrl_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pgctrl_write,
	.release = single_release,
592 593 594
};

static int pktgen_if_show(struct seq_file *seq, void *v)
L
Linus Torvalds 已提交
595 596
{
	int i;
L
Luiz Capitulino 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610
	struct pktgen_dev *pkt_dev = seq->private;
	__u64 sa;
	__u64 stopped;
	__u64 now = getCurUs();

	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,
		   "     frags: %d  delay: %u  clone_skb: %d  ifname: %s\n",
		   pkt_dev->nfrags,
		   1000 * pkt_dev->delay_us + pkt_dev->delay_ns,
611
		   pkt_dev->clone_skb, pkt_dev->odev->name);
L
Luiz Capitulino 已提交
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636

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

	if (pkt_dev->flags & F_IPV6) {
		char b1[128], b2[128], b3[128];
		fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr);
		fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr);
		fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr);
		seq_printf(seq,
			   "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1,
			   b2, b3);

		fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr);
		fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr);
		fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr);
		seq_printf(seq,
			   "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1,
			   b2, b3);

	} else
		seq_printf(seq,
			   "     dst_min: %s  dst_max: %s\n     src_min: %s  src_max: %s\n",
			   pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min,
			   pkt_dev->src_max);
L
Linus Torvalds 已提交
637

L
Luiz Capitulino 已提交
638
	seq_puts(seq, "     src_mac: ");
L
Linus Torvalds 已提交
639

L
Luiz Capitulino 已提交
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
	if (is_zero_ether_addr(pkt_dev->src_mac))
		for (i = 0; i < 6; i++)
			seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i],
				   i == 5 ? "  " : ":");
	else
		for (i = 0; i < 6; i++)
			seq_printf(seq, "%02X%s", pkt_dev->src_mac[i],
				   i == 5 ? "  " : ":");

	seq_printf(seq, "dst_mac: ");
	for (i = 0; i < 6; i++)
		seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i],
			   i == 5 ? "\n" : ":");

	seq_printf(seq,
		   "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
		   pkt_dev->udp_src_min, pkt_dev->udp_src_max,
		   pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);

	seq_printf(seq,
660
		   "     src_mac_count: %d  dst_mac_count: %d\n",
L
Luiz Capitulino 已提交
661
		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
L
Linus Torvalds 已提交
662

663 664 665
	if (pkt_dev->nr_labels) {
		unsigned i;
		seq_printf(seq, "     mpls: ");
666
		for (i = 0; i < pkt_dev->nr_labels; i++)
667 668 669 670
			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
	}

F
Francesco Fondelli 已提交
671 672 673 674 675 676 677 678 679 680
	if (pkt_dev->vlan_id != 0xffff) {
		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
			   pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi);
	}

	if (pkt_dev->svlan_id != 0xffff) {
		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
			   pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi);
	}

F
Francesco Fondelli 已提交
681 682 683 684 685 686 687 688
	if (pkt_dev->tos) {
		seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);
	}

	if (pkt_dev->traffic_class) {
		seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
	}

689 690
	seq_printf(seq, "     Flags: ");

L
Luiz Capitulino 已提交
691 692
	if (pkt_dev->flags & F_IPV6)
		seq_printf(seq, "IPV6  ");
L
Linus Torvalds 已提交
693

L
Luiz Capitulino 已提交
694 695
	if (pkt_dev->flags & F_IPSRC_RND)
		seq_printf(seq, "IPSRC_RND  ");
L
Linus Torvalds 已提交
696

L
Luiz Capitulino 已提交
697 698
	if (pkt_dev->flags & F_IPDST_RND)
		seq_printf(seq, "IPDST_RND  ");
L
Linus Torvalds 已提交
699

L
Luiz Capitulino 已提交
700 701
	if (pkt_dev->flags & F_TXSIZE_RND)
		seq_printf(seq, "TXSIZE_RND  ");
L
Linus Torvalds 已提交
702

L
Luiz Capitulino 已提交
703 704
	if (pkt_dev->flags & F_UDPSRC_RND)
		seq_printf(seq, "UDPSRC_RND  ");
L
Linus Torvalds 已提交
705

L
Luiz Capitulino 已提交
706 707
	if (pkt_dev->flags & F_UDPDST_RND)
		seq_printf(seq, "UDPDST_RND  ");
L
Linus Torvalds 已提交
708

709 710 711
	if (pkt_dev->flags & F_MPLS_RND)
		seq_printf(seq,  "MPLS_RND  ");

712 713 714 715 716 717 718
	if (pkt_dev->cflows) {
		if (pkt_dev->flags & F_FLOW_SEQ)
			seq_printf(seq,  "FLOW_SEQ  "); /*in sequence flows*/
		else
			seq_printf(seq,  "FLOW_RND  ");
	}

J
Jamal Hadi Salim 已提交
719 720 721 722 723
#ifdef CONFIG_XFRM
	if (pkt_dev->flags & F_IPSEC_ON)
		seq_printf(seq,  "IPSEC  ");
#endif

L
Luiz Capitulino 已提交
724 725
	if (pkt_dev->flags & F_MACSRC_RND)
		seq_printf(seq, "MACSRC_RND  ");
L
Linus Torvalds 已提交
726

L
Luiz Capitulino 已提交
727 728
	if (pkt_dev->flags & F_MACDST_RND)
		seq_printf(seq, "MACDST_RND  ");
L
Linus Torvalds 已提交
729

F
Francesco Fondelli 已提交
730 731 732 733 734 735
	if (pkt_dev->flags & F_VID_RND)
		seq_printf(seq, "VID_RND  ");

	if (pkt_dev->flags & F_SVID_RND)
		seq_printf(seq, "SVID_RND  ");

L
Luiz Capitulino 已提交
736 737 738 739 740 741
	seq_puts(seq, "\n");

	sa = pkt_dev->started_at;
	stopped = pkt_dev->stopped_at;
	if (pkt_dev->running)
		stopped = now;	/* not really stopped, more like last-running-at */
L
Linus Torvalds 已提交
742

L
Luiz Capitulino 已提交
743 744 745 746 747 748
	seq_printf(seq,
		   "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %lluus  stopped: %lluus idle: %lluus\n",
		   (unsigned long long)pkt_dev->sofar,
		   (unsigned long long)pkt_dev->errors, (unsigned long long)sa,
		   (unsigned long long)stopped,
		   (unsigned long long)pkt_dev->idle_acc);
L
Linus Torvalds 已提交
749

L
Luiz Capitulino 已提交
750 751
	seq_printf(seq,
		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
752 753
		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
		   pkt_dev->cur_src_mac_offset);
L
Linus Torvalds 已提交
754

L
Luiz Capitulino 已提交
755
	if (pkt_dev->flags & F_IPV6) {
L
Linus Torvalds 已提交
756
		char b1[128], b2[128];
L
Luiz Capitulino 已提交
757 758 759 760 761
		fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr);
		fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr);
		seq_printf(seq, "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
	} else
		seq_printf(seq, "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
762
			   pkt_dev->cur_saddr, pkt_dev->cur_daddr);
L
Linus Torvalds 已提交
763

L
Luiz Capitulino 已提交
764
	seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
765
		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
L
Linus Torvalds 已提交
766

L
Luiz Capitulino 已提交
767
	seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
L
Linus Torvalds 已提交
768 769

	if (pkt_dev->result[0])
L
Luiz Capitulino 已提交
770
		seq_printf(seq, "Result: %s\n", pkt_dev->result);
L
Linus Torvalds 已提交
771
	else
L
Luiz Capitulino 已提交
772
		seq_printf(seq, "Result: Idle\n");
L
Linus Torvalds 已提交
773

774
	return 0;
L
Linus Torvalds 已提交
775 776
}

777

F
Francesco Fondelli 已提交
778
static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num)
779 780 781 782
{
	int i = 0;
	*num = 0;

783
	for (; i < maxlen; i++) {
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
		char c;
		*num <<= 4;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		if ((c >= '0') && (c <= '9'))
			*num |= c - '0';
		else if ((c >= 'a') && (c <= 'f'))
			*num |= c - 'a' + 10;
		else if ((c >= 'A') && (c <= 'F'))
			*num |= c - 'A' + 10;
		else
			break;
	}
	return i;
}

L
Luiz Capitulino 已提交
800 801
static int count_trail_chars(const char __user * user_buffer,
			     unsigned int maxlen)
L
Linus Torvalds 已提交
802 803 804 805
{
	int i;

	for (i = 0; i < maxlen; i++) {
L
Luiz Capitulino 已提交
806 807 808 809
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
L
Linus Torvalds 已提交
810 811 812 813 814 815 816 817 818
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
		case '=':
			break;
		default:
			goto done;
819
		}
L
Linus Torvalds 已提交
820 821 822 823 824
	}
done:
	return i;
}

L
Luiz Capitulino 已提交
825 826
static unsigned long num_arg(const char __user * user_buffer,
			     unsigned long maxlen, unsigned long *num)
L
Linus Torvalds 已提交
827 828 829
{
	int i = 0;
	*num = 0;
L
Luiz Capitulino 已提交
830 831 832 833 834 835

	for (; i < maxlen; i++) {
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		if ((c >= '0') && (c <= '9')) {
L
Linus Torvalds 已提交
836
			*num *= 10;
L
Luiz Capitulino 已提交
837
			*num += c - '0';
L
Linus Torvalds 已提交
838 839 840 841 842 843
		} else
			break;
	}
	return i;
}

L
Luiz Capitulino 已提交
844
static int strn_len(const char __user * user_buffer, unsigned int maxlen)
L
Linus Torvalds 已提交
845 846 847
{
	int i = 0;

L
Luiz Capitulino 已提交
848 849 850 851 852
	for (; i < maxlen; i++) {
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
L
Linus Torvalds 已提交
853 854 855 856 857 858 859 860 861
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
			goto done_str;
			break;
		default:
			break;
862
		}
L
Linus Torvalds 已提交
863 864 865 866 867
	}
done_str:
	return i;
}

868 869 870 871 872 873 874 875 876 877
static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
{
	unsigned n = 0;
	char c;
	ssize_t i = 0;
	int len;

	pkt_dev->nr_labels = 0;
	do {
		__u32 tmp;
F
Francesco Fondelli 已提交
878
		len = hex32_arg(&buffer[i], 8, &tmp);
879 880 881 882 883 884 885 886 887 888 889 890
		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;
891
	} while (c == ',');
892 893 894 895 896

	pkt_dev->nr_labels = n;
	return i;
}

L
Luiz Capitulino 已提交
897 898 899
static ssize_t pktgen_if_write(struct file *file,
			       const char __user * user_buffer, size_t count,
			       loff_t * offset)
L
Linus Torvalds 已提交
900
{
L
Luiz Capitulino 已提交
901 902
	struct seq_file *seq = (struct seq_file *)file->private_data;
	struct pktgen_dev *pkt_dev = seq->private;
L
Linus Torvalds 已提交
903 904 905
	int i = 0, max, len;
	char name[16], valstr[32];
	unsigned long value = 0;
L
Luiz Capitulino 已提交
906 907
	char *pg_result = NULL;
	int tmp = 0;
L
Linus Torvalds 已提交
908
	char buf[128];
L
Luiz Capitulino 已提交
909 910 911

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

L
Linus Torvalds 已提交
912
	if (count < 1) {
913
		printk(KERN_WARNING "pktgen: wrong command format\n");
L
Linus Torvalds 已提交
914 915
		return -EINVAL;
	}
L
Luiz Capitulino 已提交
916

L
Linus Torvalds 已提交
917 918
	max = count - i;
	tmp = count_trail_chars(&user_buffer[i], max);
L
Luiz Capitulino 已提交
919
	if (tmp < 0) {
920
		printk(KERN_WARNING "pktgen: illegal format\n");
L
Luiz Capitulino 已提交
921
		return tmp;
L
Linus Torvalds 已提交
922
	}
L
Luiz Capitulino 已提交
923 924
	i += tmp;

L
Linus Torvalds 已提交
925 926 927
	/* Read variable name */

	len = strn_len(&user_buffer[i], sizeof(name) - 1);
L
Luiz Capitulino 已提交
928 929 930
	if (len < 0) {
		return len;
	}
L
Linus Torvalds 已提交
931
	memset(name, 0, sizeof(name));
L
Luiz Capitulino 已提交
932
	if (copy_from_user(name, &user_buffer[i], len))
L
Linus Torvalds 已提交
933 934
		return -EFAULT;
	i += len;
L
Luiz Capitulino 已提交
935 936

	max = count - i;
L
Linus Torvalds 已提交
937
	len = count_trail_chars(&user_buffer[i], max);
L
Luiz Capitulino 已提交
938 939 940
	if (len < 0)
		return len;

L
Linus Torvalds 已提交
941 942 943
	i += len;

	if (debug) {
L
Luiz Capitulino 已提交
944 945
		char tb[count + 1];
		if (copy_from_user(tb, user_buffer, count))
L
Linus Torvalds 已提交
946
			return -EFAULT;
L
Luiz Capitulino 已提交
947
		tb[count] = 0;
948
		printk(KERN_DEBUG "pktgen: %s,%lu  buffer -:%s:-\n", name,
L
Luiz Capitulino 已提交
949 950
		       (unsigned long)count, tb);
	}
L
Linus Torvalds 已提交
951 952 953

	if (!strcmp(name, "min_pkt_size")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
954 955 956
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
957
		i += len;
L
Luiz Capitulino 已提交
958 959 960 961 962 963 964 965
		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);
L
Linus Torvalds 已提交
966 967 968
		return count;
	}

L
Luiz Capitulino 已提交
969
	if (!strcmp(name, "max_pkt_size")) {
L
Linus Torvalds 已提交
970
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
971 972 973
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
974
		i += len;
L
Luiz Capitulino 已提交
975 976 977 978 979 980 981 982
		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);
L
Linus Torvalds 已提交
983 984 985
		return count;
	}

L
Luiz Capitulino 已提交
986
	/* Shortcut for min = max */
L
Linus Torvalds 已提交
987 988 989

	if (!strcmp(name, "pkt_size")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
990 991 992
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
993
		i += len;
L
Luiz Capitulino 已提交
994 995 996 997 998 999 1000
		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;
		}
L
Linus Torvalds 已提交
1001 1002 1003 1004
		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
		return count;
	}

L
Luiz Capitulino 已提交
1005
	if (!strcmp(name, "debug")) {
L
Linus Torvalds 已提交
1006
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1007 1008 1009
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1010
		i += len;
L
Luiz Capitulino 已提交
1011
		debug = value;
L
Linus Torvalds 已提交
1012 1013 1014 1015
		sprintf(pg_result, "OK: debug=%u", debug);
		return count;
	}

L
Luiz Capitulino 已提交
1016
	if (!strcmp(name, "frags")) {
L
Linus Torvalds 已提交
1017
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1018 1019 1020
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1021 1022 1023 1024 1025 1026 1027
		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);
L
Luiz Capitulino 已提交
1028 1029 1030
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1031 1032 1033 1034 1035 1036 1037 1038
		i += len;
		if (value == 0x7FFFFFFF) {
			pkt_dev->delay_us = 0x7FFFFFFF;
			pkt_dev->delay_ns = 0;
		} else {
			pkt_dev->delay_us = value / 1000;
			pkt_dev->delay_ns = value % 1000;
		}
L
Luiz Capitulino 已提交
1039 1040
		sprintf(pg_result, "OK: delay=%u",
			1000 * pkt_dev->delay_us + pkt_dev->delay_ns);
L
Linus Torvalds 已提交
1041 1042
		return count;
	}
L
Luiz Capitulino 已提交
1043
	if (!strcmp(name, "udp_src_min")) {
L
Linus Torvalds 已提交
1044
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1045 1046 1047
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1048
		i += len;
L
Luiz Capitulino 已提交
1049 1050 1051 1052
		if (value != pkt_dev->udp_src_min) {
			pkt_dev->udp_src_min = value;
			pkt_dev->cur_udp_src = value;
		}
L
Linus Torvalds 已提交
1053 1054 1055
		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
		return count;
	}
L
Luiz Capitulino 已提交
1056
	if (!strcmp(name, "udp_dst_min")) {
L
Linus Torvalds 已提交
1057
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1058 1059 1060
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1061
		i += len;
L
Luiz Capitulino 已提交
1062 1063 1064 1065
		if (value != pkt_dev->udp_dst_min) {
			pkt_dev->udp_dst_min = value;
			pkt_dev->cur_udp_dst = value;
		}
L
Linus Torvalds 已提交
1066 1067 1068
		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
		return count;
	}
L
Luiz Capitulino 已提交
1069
	if (!strcmp(name, "udp_src_max")) {
L
Linus Torvalds 已提交
1070
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1071 1072 1073
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1074
		i += len;
L
Luiz Capitulino 已提交
1075 1076 1077 1078
		if (value != pkt_dev->udp_src_max) {
			pkt_dev->udp_src_max = value;
			pkt_dev->cur_udp_src = value;
		}
L
Linus Torvalds 已提交
1079 1080 1081
		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
		return count;
	}
L
Luiz Capitulino 已提交
1082
	if (!strcmp(name, "udp_dst_max")) {
L
Linus Torvalds 已提交
1083
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1084 1085 1086
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1087
		i += len;
L
Luiz Capitulino 已提交
1088 1089 1090 1091
		if (value != pkt_dev->udp_dst_max) {
			pkt_dev->udp_dst_max = value;
			pkt_dev->cur_udp_dst = value;
		}
L
Linus Torvalds 已提交
1092 1093 1094 1095 1096
		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);
L
Luiz Capitulino 已提交
1097 1098 1099
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1100
		i += len;
L
Luiz Capitulino 已提交
1101 1102
		pkt_dev->clone_skb = value;

L
Linus Torvalds 已提交
1103 1104 1105 1106 1107
		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);
L
Luiz Capitulino 已提交
1108 1109 1110
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1111 1112 1113
		i += len;
		pkt_dev->count = value;
		sprintf(pg_result, "OK: count=%llu",
L
Luiz Capitulino 已提交
1114
			(unsigned long long)pkt_dev->count);
L
Linus Torvalds 已提交
1115 1116 1117 1118
		return count;
	}
	if (!strcmp(name, "src_mac_count")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1119 1120 1121
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1122 1123
		i += len;
		if (pkt_dev->src_mac_count != value) {
L
Luiz Capitulino 已提交
1124 1125 1126 1127 1128
			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);
L
Linus Torvalds 已提交
1129 1130 1131 1132
		return count;
	}
	if (!strcmp(name, "dst_mac_count")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1133 1134 1135
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1136 1137
		i += len;
		if (pkt_dev->dst_mac_count != value) {
L
Luiz Capitulino 已提交
1138 1139 1140 1141 1142
			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);
L
Linus Torvalds 已提交
1143 1144 1145
		return count;
	}
	if (!strcmp(name, "flag")) {
L
Luiz Capitulino 已提交
1146 1147
		char f[32];
		memset(f, 0, 32);
L
Linus Torvalds 已提交
1148
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
L
Luiz Capitulino 已提交
1149 1150 1151
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1152 1153 1154
		if (copy_from_user(f, &user_buffer[i], len))
			return -EFAULT;
		i += len;
L
Luiz Capitulino 已提交
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
		if (strcmp(f, "IPSRC_RND") == 0)
			pkt_dev->flags |= F_IPSRC_RND;

		else if (strcmp(f, "!IPSRC_RND") == 0)
			pkt_dev->flags &= ~F_IPSRC_RND;

		else if (strcmp(f, "TXSIZE_RND") == 0)
			pkt_dev->flags |= F_TXSIZE_RND;

		else if (strcmp(f, "!TXSIZE_RND") == 0)
			pkt_dev->flags &= ~F_TXSIZE_RND;

		else if (strcmp(f, "IPDST_RND") == 0)
			pkt_dev->flags |= F_IPDST_RND;

		else if (strcmp(f, "!IPDST_RND") == 0)
			pkt_dev->flags &= ~F_IPDST_RND;

		else if (strcmp(f, "UDPSRC_RND") == 0)
			pkt_dev->flags |= F_UDPSRC_RND;

		else if (strcmp(f, "!UDPSRC_RND") == 0)
			pkt_dev->flags &= ~F_UDPSRC_RND;

		else if (strcmp(f, "UDPDST_RND") == 0)
			pkt_dev->flags |= F_UDPDST_RND;

		else if (strcmp(f, "!UDPDST_RND") == 0)
			pkt_dev->flags &= ~F_UDPDST_RND;

		else if (strcmp(f, "MACSRC_RND") == 0)
			pkt_dev->flags |= F_MACSRC_RND;

		else if (strcmp(f, "!MACSRC_RND") == 0)
			pkt_dev->flags &= ~F_MACSRC_RND;

		else if (strcmp(f, "MACDST_RND") == 0)
			pkt_dev->flags |= F_MACDST_RND;

		else if (strcmp(f, "!MACDST_RND") == 0)
			pkt_dev->flags &= ~F_MACDST_RND;

1197 1198 1199 1200 1201 1202
		else if (strcmp(f, "MPLS_RND") == 0)
			pkt_dev->flags |= F_MPLS_RND;

		else if (strcmp(f, "!MPLS_RND") == 0)
			pkt_dev->flags &= ~F_MPLS_RND;

F
Francesco Fondelli 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
		else if (strcmp(f, "VID_RND") == 0)
			pkt_dev->flags |= F_VID_RND;

		else if (strcmp(f, "!VID_RND") == 0)
			pkt_dev->flags &= ~F_VID_RND;

		else if (strcmp(f, "SVID_RND") == 0)
			pkt_dev->flags |= F_SVID_RND;

		else if (strcmp(f, "!SVID_RND") == 0)
			pkt_dev->flags &= ~F_SVID_RND;

1215 1216 1217
		else if (strcmp(f, "FLOW_SEQ") == 0)
			pkt_dev->flags |= F_FLOW_SEQ;

J
Jamal Hadi Salim 已提交
1218 1219 1220 1221 1222
#ifdef CONFIG_XFRM
		else if (strcmp(f, "IPSEC") == 0)
			pkt_dev->flags |= F_IPSEC_ON;
#endif

F
Francesco Fondelli 已提交
1223 1224 1225
		else if (strcmp(f, "!IPV6") == 0)
			pkt_dev->flags &= ~F_IPV6;

L
Luiz Capitulino 已提交
1226 1227 1228 1229
		else {
			sprintf(pg_result,
				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
				f,
F
Francesco Fondelli 已提交
1230
				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
J
Jamal Hadi Salim 已提交
1231
				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n");
L
Luiz Capitulino 已提交
1232 1233
			return count;
		}
L
Linus Torvalds 已提交
1234 1235 1236 1237 1238
		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);
L
Luiz Capitulino 已提交
1239 1240 1241
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1242

L
Luiz Capitulino 已提交
1243
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1244
			return -EFAULT;
L
Luiz Capitulino 已提交
1245 1246 1247 1248 1249 1250 1251 1252
		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)
1253
			printk(KERN_DEBUG "pktgen: dst_min set to: %s\n",
L
Luiz Capitulino 已提交
1254 1255
			       pkt_dev->dst_min);
		i += len;
L
Linus Torvalds 已提交
1256 1257 1258 1259 1260
		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);
L
Luiz Capitulino 已提交
1261 1262 1263
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1264

L
Luiz Capitulino 已提交
1265
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1266 1267
			return -EFAULT;

L
Luiz Capitulino 已提交
1268 1269 1270 1271 1272 1273 1274 1275
		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)
1276
			printk(KERN_DEBUG "pktgen: dst_max set to: %s\n",
L
Luiz Capitulino 已提交
1277
			       pkt_dev->dst_max);
L
Linus Torvalds 已提交
1278 1279 1280 1281 1282 1283
		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);
L
Luiz Capitulino 已提交
1284 1285
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1286 1287 1288

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1289
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1290
			return -EFAULT;
L
Luiz Capitulino 已提交
1291
		buf[len] = 0;
L
Linus Torvalds 已提交
1292 1293

		scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
L
Luiz Capitulino 已提交
1294
		fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
L
Linus Torvalds 已提交
1295 1296 1297

		ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);

L
Luiz Capitulino 已提交
1298
		if (debug)
1299
			printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf);
L
Linus Torvalds 已提交
1300

L
Luiz Capitulino 已提交
1301
		i += len;
L
Linus Torvalds 已提交
1302 1303 1304 1305 1306
		sprintf(pg_result, "OK: dst6=%s", buf);
		return count;
	}
	if (!strcmp(name, "dst6_min")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
L
Luiz Capitulino 已提交
1307 1308
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1309 1310 1311

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1312
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1313
			return -EFAULT;
L
Luiz Capitulino 已提交
1314
		buf[len] = 0;
L
Linus Torvalds 已提交
1315 1316

		scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
L
Luiz Capitulino 已提交
1317
		fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
L
Linus Torvalds 已提交
1318

L
Luiz Capitulino 已提交
1319 1320 1321
		ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
			       &pkt_dev->min_in6_daddr);
		if (debug)
1322
			printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
L
Linus Torvalds 已提交
1323

L
Luiz Capitulino 已提交
1324
		i += len;
L
Linus Torvalds 已提交
1325 1326 1327 1328 1329
		sprintf(pg_result, "OK: dst6_min=%s", buf);
		return count;
	}
	if (!strcmp(name, "dst6_max")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
L
Luiz Capitulino 已提交
1330 1331
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1332 1333 1334

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1335
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1336
			return -EFAULT;
L
Luiz Capitulino 已提交
1337
		buf[len] = 0;
L
Linus Torvalds 已提交
1338 1339

		scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
L
Luiz Capitulino 已提交
1340
		fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
L
Linus Torvalds 已提交
1341

L
Luiz Capitulino 已提交
1342
		if (debug)
1343
			printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
L
Linus Torvalds 已提交
1344

L
Luiz Capitulino 已提交
1345
		i += len;
L
Linus Torvalds 已提交
1346 1347 1348 1349 1350
		sprintf(pg_result, "OK: dst6_max=%s", buf);
		return count;
	}
	if (!strcmp(name, "src6")) {
		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
L
Luiz Capitulino 已提交
1351 1352
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1353 1354 1355

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1356
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1357
			return -EFAULT;
L
Luiz Capitulino 已提交
1358
		buf[len] = 0;
L
Linus Torvalds 已提交
1359 1360

		scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
L
Luiz Capitulino 已提交
1361
		fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
L
Linus Torvalds 已提交
1362 1363 1364

		ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);

L
Luiz Capitulino 已提交
1365
		if (debug)
1366
			printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
L
Luiz Capitulino 已提交
1367 1368

		i += len;
L
Linus Torvalds 已提交
1369 1370 1371 1372 1373
		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);
L
Luiz Capitulino 已提交
1374 1375 1376 1377
		if (len < 0) {
			return len;
		}
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1378
			return -EFAULT;
L
Luiz Capitulino 已提交
1379 1380 1381 1382 1383 1384 1385 1386
		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)
1387
			printk(KERN_DEBUG "pktgen: src_min set to: %s\n",
L
Luiz Capitulino 已提交
1388
			       pkt_dev->src_min);
L
Linus Torvalds 已提交
1389 1390 1391 1392 1393 1394
		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);
L
Luiz Capitulino 已提交
1395 1396 1397 1398
		if (len < 0) {
			return len;
		}
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1399
			return -EFAULT;
L
Luiz Capitulino 已提交
1400 1401 1402 1403 1404 1405 1406 1407
		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)
1408
			printk(KERN_DEBUG "pktgen: src_max set to: %s\n",
L
Luiz Capitulino 已提交
1409
			       pkt_dev->src_max);
L
Linus Torvalds 已提交
1410 1411 1412 1413 1414 1415
		i += len;
		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
		return count;
	}
	if (!strcmp(name, "dst_mac")) {
		char *v = valstr;
1416
		unsigned char old_dmac[ETH_ALEN];
L
Linus Torvalds 已提交
1417
		unsigned char *m = pkt_dev->dst_mac;
1418
		memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
L
Luiz Capitulino 已提交
1419

L
Linus Torvalds 已提交
1420
		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
L
Luiz Capitulino 已提交
1421 1422 1423
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1424
		memset(valstr, 0, sizeof(valstr));
L
Luiz Capitulino 已提交
1425
		if (copy_from_user(valstr, &user_buffer[i], len))
L
Linus Torvalds 已提交
1426 1427 1428
			return -EFAULT;
		i += len;

L
Luiz Capitulino 已提交
1429
		for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
L
Linus Torvalds 已提交
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
			if (*v >= '0' && *v <= '9') {
				*m *= 16;
				*m += *v - '0';
			}
			if (*v >= 'A' && *v <= 'F') {
				*m *= 16;
				*m += *v - 'A' + 10;
			}
			if (*v >= 'a' && *v <= 'f') {
				*m *= 16;
				*m += *v - 'a' + 10;
			}
			if (*v == ':') {
				m++;
				*m = 0;
			}
		}

		/* Set up Dest MAC */
1449 1450
		if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
			memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
L
Luiz Capitulino 已提交
1451

L
Linus Torvalds 已提交
1452 1453 1454 1455 1456
		sprintf(pg_result, "OK: dstmac");
		return count;
	}
	if (!strcmp(name, "src_mac")) {
		char *v = valstr;
A
Adit Ranadive 已提交
1457
		unsigned char old_smac[ETH_ALEN];
L
Linus Torvalds 已提交
1458 1459
		unsigned char *m = pkt_dev->src_mac;

A
Adit Ranadive 已提交
1460 1461
		memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);

L
Linus Torvalds 已提交
1462
		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
L
Luiz Capitulino 已提交
1463 1464 1465
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1466
		memset(valstr, 0, sizeof(valstr));
L
Luiz Capitulino 已提交
1467
		if (copy_from_user(valstr, &user_buffer[i], len))
L
Linus Torvalds 已提交
1468 1469 1470
			return -EFAULT;
		i += len;

L
Luiz Capitulino 已提交
1471
		for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
L
Linus Torvalds 已提交
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
			if (*v >= '0' && *v <= '9') {
				*m *= 16;
				*m += *v - '0';
			}
			if (*v >= 'A' && *v <= 'F') {
				*m *= 16;
				*m += *v - 'A' + 10;
			}
			if (*v >= 'a' && *v <= 'f') {
				*m *= 16;
				*m += *v - 'a' + 10;
			}
			if (*v == ':') {
				m++;
				*m = 0;
			}
L
Luiz Capitulino 已提交
1488
		}
L
Linus Torvalds 已提交
1489

A
Adit Ranadive 已提交
1490 1491 1492 1493
		/* Set up Src MAC */
		if (compare_ether_addr(old_smac, pkt_dev->src_mac))
			memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);

L
Luiz Capitulino 已提交
1494
		sprintf(pg_result, "OK: srcmac");
L
Linus Torvalds 已提交
1495 1496 1497
		return count;
	}

L
Luiz Capitulino 已提交
1498 1499 1500 1501 1502
	if (!strcmp(name, "clear_counters")) {
		pktgen_clear_counters(pkt_dev);
		sprintf(pg_result, "OK: Clearing counters.\n");
		return count;
	}
L
Linus Torvalds 已提交
1503 1504 1505

	if (!strcmp(name, "flows")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1506 1507 1508
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
		i += len;
		if (value > MAX_CFLOWS)
			value = MAX_CFLOWS;

		pkt_dev->cflows = value;
		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
		return count;
	}

	if (!strcmp(name, "flowlen")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1520 1521 1522
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1523 1524 1525 1526 1527
		i += len;
		pkt_dev->lflow = value;
		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
		return count;
	}
L
Luiz Capitulino 已提交
1528

1529 1530 1531 1532 1533 1534
	if (!strcmp(name, "mpls")) {
		unsigned n, offset;
		len = get_labels(&user_buffer[i], pkt_dev);
		if (len < 0) { return len; }
		i += len;
		offset = sprintf(pg_result, "OK: mpls=");
1535
		for (n = 0; n < pkt_dev->nr_labels; n++)
1536 1537 1538
			offset += sprintf(pg_result + offset,
					  "%08x%s", ntohl(pkt_dev->labels[n]),
					  n == pkt_dev->nr_labels-1 ? "" : ",");
F
Francesco Fondelli 已提交
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)
1545
				printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n");
F
Francesco Fondelli 已提交
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
		}
		return count;
	}

	if (!strcmp(name, "vlan_id")) {
		len = num_arg(&user_buffer[i], 4, &value);
		if (len < 0) {
			return len;
		}
		i += len;
		if (value <= 4095) {
			pkt_dev->vlan_id = value;  /* turn on VLAN */

			if (debug)
1560
				printk(KERN_DEBUG "pktgen: VLAN turned on\n");
F
Francesco Fondelli 已提交
1561 1562

			if (debug && pkt_dev->nr_labels)
1563
				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
F
Francesco Fondelli 已提交
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)
1572
				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
F
Francesco Fondelli 已提交
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
		}
		return count;
	}

	if (!strcmp(name, "vlan_p")) {
		len = num_arg(&user_buffer[i], 1, &value);
		if (len < 0) {
			return len;
		}
		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);
		if (len < 0) {
			return len;
		}
		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);
		if (len < 0) {
			return len;
		}
		i += len;
		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
			pkt_dev->svlan_id = value;  /* turn on SVLAN */

			if (debug)
1617
				printk(KERN_DEBUG "pktgen: SVLAN turned on\n");
F
Francesco Fondelli 已提交
1618 1619

			if (debug && pkt_dev->nr_labels)
1620
				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
F
Francesco Fondelli 已提交
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)
1629
				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
F
Francesco Fondelli 已提交
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660
		}
		return count;
	}

	if (!strcmp(name, "svlan_p")) {
		len = num_arg(&user_buffer[i], 1, &value);
		if (len < 0) {
			return len;
		}
		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);
		if (len < 0) {
			return len;
		}
		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;
	}

F
Francesco Fondelli 已提交
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
	if (!strcmp(name, "tos")) {
		__u32 tmp_value = 0;
		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
		if (len < 0) {
			return len;
		}
		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);
		if (len < 0) {
			return len;
		}
		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;
	}

L
Linus Torvalds 已提交
1696 1697 1698 1699
	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
	return -EINVAL;
}

1700
static int pktgen_if_open(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
1701
{
1702 1703
	return single_open(file, pktgen_if_show, PDE(inode)->data);
}
L
Linus Torvalds 已提交
1704

1705
static const struct file_operations pktgen_if_fops = {
L
Luiz Capitulino 已提交
1706 1707 1708 1709 1710 1711
	.owner   = THIS_MODULE,
	.open    = pktgen_if_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pktgen_if_write,
	.release = single_release,
1712
};
L
Linus Torvalds 已提交
1713

1714 1715
static int pktgen_thread_show(struct seq_file *seq, void *v)
{
L
Luiz Capitulino 已提交
1716
	struct pktgen_thread *t = seq->private;
1717
	struct pktgen_dev *pkt_dev;
1718 1719

	BUG_ON(!t);
L
Linus Torvalds 已提交
1720

1721
	seq_printf(seq, "Name: %s  max_before_softirq: %d\n",
1722
		   t->tsk->comm, t->max_before_softirq);
L
Luiz Capitulino 已提交
1723 1724

	seq_printf(seq, "Running: ");
L
Linus Torvalds 已提交
1725

L
Luiz Capitulino 已提交
1726
	if_lock(t);
1727
	list_for_each_entry(pkt_dev, &t->if_list, list)
L
Luiz Capitulino 已提交
1728
		if (pkt_dev->running)
1729
			seq_printf(seq, "%s ", pkt_dev->odev->name);
L
Linus Torvalds 已提交
1730

L
Luiz Capitulino 已提交
1731 1732
	seq_printf(seq, "\nStopped: ");

1733
	list_for_each_entry(pkt_dev, &t->if_list, list)
L
Luiz Capitulino 已提交
1734
		if (!pkt_dev->running)
1735
			seq_printf(seq, "%s ", pkt_dev->odev->name);
L
Linus Torvalds 已提交
1736 1737

	if (t->result[0])
1738
		seq_printf(seq, "\nResult: %s\n", t->result);
L
Linus Torvalds 已提交
1739
	else
1740
		seq_printf(seq, "\nResult: NA\n");
L
Linus Torvalds 已提交
1741

L
Luiz Capitulino 已提交
1742
	if_unlock(t);
L
Linus Torvalds 已提交
1743

1744
	return 0;
L
Linus Torvalds 已提交
1745 1746
}

1747
static ssize_t pktgen_thread_write(struct file *file,
L
Luiz Capitulino 已提交
1748 1749
				   const char __user * user_buffer,
				   size_t count, loff_t * offset)
L
Linus Torvalds 已提交
1750
{
L
Luiz Capitulino 已提交
1751 1752
	struct seq_file *seq = (struct seq_file *)file->private_data;
	struct pktgen_thread *t = seq->private;
L
Linus Torvalds 已提交
1753 1754
	int i = 0, max, len, ret;
	char name[40];
L
Luiz Capitulino 已提交
1755 1756
	char *pg_result;
	unsigned long value = 0;
1757

L
Linus Torvalds 已提交
1758
	if (count < 1) {
L
Luiz Capitulino 已提交
1759
		//      sprintf(pg_result, "Wrong command format");
L
Linus Torvalds 已提交
1760 1761
		return -EINVAL;
	}
1762

L
Linus Torvalds 已提交
1763
	max = count - i;
L
Luiz Capitulino 已提交
1764 1765
	len = count_trail_chars(&user_buffer[i], max);
	if (len < 0)
1766 1767
		return len;

L
Linus Torvalds 已提交
1768
	i += len;
1769

L
Linus Torvalds 已提交
1770 1771 1772
	/* Read variable name */

	len = strn_len(&user_buffer[i], sizeof(name) - 1);
L
Luiz Capitulino 已提交
1773
	if (len < 0)
1774
		return len;
L
Luiz Capitulino 已提交
1775

L
Linus Torvalds 已提交
1776 1777 1778 1779
	memset(name, 0, sizeof(name));
	if (copy_from_user(name, &user_buffer[i], len))
		return -EFAULT;
	i += len;
1780

L
Luiz Capitulino 已提交
1781
	max = count - i;
L
Linus Torvalds 已提交
1782
	len = count_trail_chars(&user_buffer[i], max);
L
Luiz Capitulino 已提交
1783
	if (len < 0)
1784 1785
		return len;

L
Linus Torvalds 已提交
1786 1787
	i += len;

1788
	if (debug)
1789 1790
		printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n",
		       name, (unsigned long)count);
L
Linus Torvalds 已提交
1791

L
Luiz Capitulino 已提交
1792
	if (!t) {
1793
		printk(KERN_ERR "pktgen: ERROR: No thread\n");
L
Linus Torvalds 已提交
1794 1795 1796 1797 1798 1799
		ret = -EINVAL;
		goto out;
	}

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

L
Luiz Capitulino 已提交
1800 1801 1802
	if (!strcmp(name, "add_device")) {
		char f[32];
		memset(f, 0, 32);
L
Linus Torvalds 已提交
1803
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
L
Luiz Capitulino 已提交
1804 1805
		if (len < 0) {
			ret = len;
L
Linus Torvalds 已提交
1806 1807
			goto out;
		}
L
Luiz Capitulino 已提交
1808
		if (copy_from_user(f, &user_buffer[i], len))
L
Linus Torvalds 已提交
1809 1810
			return -EFAULT;
		i += len;
1811
		mutex_lock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1812
		pktgen_add_device(t, f);
1813
		mutex_unlock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1814 1815
		ret = count;
		sprintf(pg_result, "OK: add_device=%s", f);
L
Linus Torvalds 已提交
1816 1817 1818
		goto out;
	}

L
Luiz Capitulino 已提交
1819
	if (!strcmp(name, "rem_device_all")) {
1820
		mutex_lock(&pktgen_thread_lock);
1821
		t->control |= T_REMDEVALL;
1822
		mutex_unlock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1823
		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
L
Linus Torvalds 已提交
1824
		ret = count;
L
Luiz Capitulino 已提交
1825
		sprintf(pg_result, "OK: rem_device_all");
L
Linus Torvalds 已提交
1826 1827 1828
		goto out;
	}

L
Luiz Capitulino 已提交
1829 1830
	if (!strcmp(name, "max_before_softirq")) {
		len = num_arg(&user_buffer[i], 10, &value);
1831
		mutex_lock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1832
		t->max_before_softirq = value;
1833
		mutex_unlock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1834 1835
		ret = count;
		sprintf(pg_result, "OK: max_before_softirq=%lu", value);
L
Linus Torvalds 已提交
1836 1837 1838 1839
		goto out;
	}

	ret = -EINVAL;
L
Luiz Capitulino 已提交
1840
out:
L
Linus Torvalds 已提交
1841 1842 1843
	return ret;
}

1844
static int pktgen_thread_open(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
1845
{
1846
	return single_open(file, pktgen_thread_show, PDE(inode)->data);
L
Linus Torvalds 已提交
1847 1848
}

1849
static const struct file_operations pktgen_thread_fops = {
L
Luiz Capitulino 已提交
1850 1851 1852 1853 1854 1855
	.owner   = THIS_MODULE,
	.open    = pktgen_thread_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pktgen_thread_write,
	.release = single_release,
1856
};
L
Linus Torvalds 已提交
1857 1858

/* Think find or remove for NN */
L
Luiz Capitulino 已提交
1859
static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
L
Linus Torvalds 已提交
1860 1861 1862 1863
{
	struct pktgen_thread *t;
	struct pktgen_dev *pkt_dev = NULL;

1864
	list_for_each_entry(t, &pktgen_threads, th_list) {
L
Linus Torvalds 已提交
1865 1866
		pkt_dev = pktgen_find_dev(t, ifname);
		if (pkt_dev) {
L
Luiz Capitulino 已提交
1867 1868 1869 1870 1871 1872
			if (remove) {
				if_lock(t);
				pkt_dev->removal_mark = 1;
				t->control |= T_REMDEV;
				if_unlock(t);
			}
L
Linus Torvalds 已提交
1873 1874 1875
			break;
		}
	}
L
Luiz Capitulino 已提交
1876
	return pkt_dev;
L
Linus Torvalds 已提交
1877 1878
}

1879 1880 1881
/*
 * mark a device for removal
 */
1882
static void pktgen_mark_device(const char *ifname)
L
Linus Torvalds 已提交
1883 1884
{
	struct pktgen_dev *pkt_dev = NULL;
1885 1886 1887
	const int max_tries = 10, msec_per_try = 125;
	int i = 0;

1888
	mutex_lock(&pktgen_thread_lock);
S
Stephen Hemminger 已提交
1889
	pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname);
1890

L
Luiz Capitulino 已提交
1891
	while (1) {
1892 1893

		pkt_dev = __pktgen_NN_threads(ifname, REMOVE);
L
Luiz Capitulino 已提交
1894 1895
		if (pkt_dev == NULL)
			break;	/* success */
1896

1897
		mutex_unlock(&pktgen_thread_lock);
S
Stephen Hemminger 已提交
1898 1899
		pr_debug("pktgen: pktgen_mark_device waiting for %s "
				"to disappear....\n", ifname);
1900
		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
1901
		mutex_lock(&pktgen_thread_lock);
1902 1903

		if (++i >= max_tries) {
1904 1905
			printk(KERN_ERR "pktgen_mark_device: timed out after "
			       "waiting %d msec for device %s to be removed\n",
L
Luiz Capitulino 已提交
1906
			       msec_per_try * i, ifname);
1907 1908 1909 1910 1911
			break;
		}

	}

1912
	mutex_unlock(&pktgen_thread_lock);
1913
}
1914

1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
static void pktgen_change_name(struct net_device *dev)
{
	struct pktgen_thread *t;

	list_for_each_entry(t, &pktgen_threads, th_list) {
		struct pktgen_dev *pkt_dev;

		list_for_each_entry(pkt_dev, &t->if_list, list) {
			if (pkt_dev->odev != dev)
				continue;

			remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);

			pkt_dev->entry = create_proc_entry(dev->name, 0600,
							   pg_proc_dir);
			if (!pkt_dev->entry)
				printk(KERN_ERR "pktgen: can't move proc "
				       " entry for '%s'\n", dev->name);
			break;
		}
	}
L
Linus Torvalds 已提交
1936 1937
}

L
Luiz Capitulino 已提交
1938 1939
static int pktgen_device_event(struct notifier_block *unused,
			       unsigned long event, void *ptr)
L
Linus Torvalds 已提交
1940
{
1941
	struct net_device *dev = ptr;
L
Linus Torvalds 已提交
1942 1943 1944 1945 1946 1947

	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
1948 1949
	case NETDEV_CHANGENAME:
		pktgen_change_name(dev);
L
Linus Torvalds 已提交
1950
		break;
L
Luiz Capitulino 已提交
1951

L
Linus Torvalds 已提交
1952
	case NETDEV_UNREGISTER:
L
Luiz Capitulino 已提交
1953
		pktgen_mark_device(dev->name);
L
Linus Torvalds 已提交
1954
		break;
1955
	}
L
Linus Torvalds 已提交
1956 1957 1958 1959 1960 1961

	return NOTIFY_DONE;
}

/* Associate pktgen_dev with a device. */

1962
static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
L
Luiz Capitulino 已提交
1963
{
L
Linus Torvalds 已提交
1964
	struct net_device *odev;
1965
	int err;
L
Linus Torvalds 已提交
1966 1967 1968 1969

	/* Clean old setups */
	if (pkt_dev->odev) {
		dev_put(pkt_dev->odev);
L
Luiz Capitulino 已提交
1970 1971
		pkt_dev->odev = NULL;
	}
L
Linus Torvalds 已提交
1972

1973
	odev = dev_get_by_name(ifname);
L
Linus Torvalds 已提交
1974
	if (!odev) {
1975
		printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname);
1976
		return -ENODEV;
L
Linus Torvalds 已提交
1977
	}
1978

L
Linus Torvalds 已提交
1979
	if (odev->type != ARPHRD_ETHER) {
1980
		printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname);
1981 1982
		err = -EINVAL;
	} else if (!netif_running(odev)) {
1983
		printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname);
1984 1985 1986 1987
		err = -ENETDOWN;
	} else {
		pkt_dev->odev = odev;
		return 0;
L
Linus Torvalds 已提交
1988 1989 1990
	}

	dev_put(odev);
1991
	return err;
L
Linus Torvalds 已提交
1992 1993 1994 1995 1996 1997 1998
}

/* 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)
{
L
Luiz Capitulino 已提交
1999
	if (!pkt_dev->odev) {
2000 2001
		printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
		       "setup_inject.\n");
L
Luiz Capitulino 已提交
2002 2003 2004 2005 2006 2007
		sprintf(pkt_dev->result,
			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
		return;
	}

	/* Default to the interface's mac if not explicitly set. */
L
Linus Torvalds 已提交
2008

2009
	if (is_zero_ether_addr(pkt_dev->src_mac))
L
Luiz Capitulino 已提交
2010
		memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN);
L
Linus Torvalds 已提交
2011

L
Luiz Capitulino 已提交
2012
	/* Set up Dest MAC */
2013
	memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
L
Linus Torvalds 已提交
2014

L
Luiz Capitulino 已提交
2015 2016 2017 2018
	/* Set up pkt size */
	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;

	if (pkt_dev->flags & F_IPV6) {
L
Linus Torvalds 已提交
2019
		/*
2020
		 * Skip this automatic address setting until locks or functions
L
Linus Torvalds 已提交
2021 2022 2023 2024
		 * gets exported
		 */

#ifdef NOTNOW
L
Luiz Capitulino 已提交
2025
		int i, set = 0, err = 1;
L
Linus Torvalds 已提交
2026 2027
		struct inet6_dev *idev;

L
Luiz Capitulino 已提交
2028 2029
		for (i = 0; i < IN6_ADDR_HSIZE; i++)
			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
L
Linus Torvalds 已提交
2030 2031 2032 2033
				set = 1;
				break;
			}

L
Luiz Capitulino 已提交
2034 2035
		if (!set) {

L
Linus Torvalds 已提交
2036 2037 2038 2039 2040 2041
			/*
			 * Use linklevel address if unconfigured.
			 *
			 * use ipv6_get_lladdr if/when it's get exported
			 */

2042
			rcu_read_lock();
L
Linus Torvalds 已提交
2043 2044 2045 2046
			if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) {
				struct inet6_ifaddr *ifp;

				read_lock_bh(&idev->lock);
L
Luiz Capitulino 已提交
2047 2048 2049 2050 2051 2052 2053 2054
				for (ifp = idev->addr_list; ifp;
				     ifp = ifp->if_next) {
					if (ifp->scope == IFA_LINK
					    && !(ifp->
						 flags & IFA_F_TENTATIVE)) {
						ipv6_addr_copy(&pkt_dev->
							       cur_in6_saddr,
							       &ifp->addr);
L
Linus Torvalds 已提交
2055 2056 2057 2058 2059 2060
						err = 0;
						break;
					}
				}
				read_unlock_bh(&idev->lock);
			}
2061
			rcu_read_unlock();
L
Luiz Capitulino 已提交
2062
			if (err)
2063 2064
				printk(KERN_ERR "pktgen: ERROR: IPv6 link "
				       "address not availble.\n");
L
Linus Torvalds 已提交
2065 2066
		}
#endif
L
Luiz Capitulino 已提交
2067
	} else {
L
Linus Torvalds 已提交
2068 2069 2070
		pkt_dev->saddr_min = 0;
		pkt_dev->saddr_max = 0;
		if (strlen(pkt_dev->src_min) == 0) {
L
Luiz Capitulino 已提交
2071 2072

			struct in_device *in_dev;
L
Linus Torvalds 已提交
2073 2074

			rcu_read_lock();
2075
			in_dev = __in_dev_get_rcu(pkt_dev->odev);
L
Linus Torvalds 已提交
2076 2077
			if (in_dev) {
				if (in_dev->ifa_list) {
L
Luiz Capitulino 已提交
2078 2079
					pkt_dev->saddr_min =
					    in_dev->ifa_list->ifa_address;
L
Linus Torvalds 已提交
2080 2081 2082 2083
					pkt_dev->saddr_max = pkt_dev->saddr_min;
				}
			}
			rcu_read_unlock();
L
Luiz Capitulino 已提交
2084
		} else {
L
Linus Torvalds 已提交
2085 2086 2087 2088 2089 2090 2091
			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);
	}
L
Luiz Capitulino 已提交
2092 2093 2094 2095 2096 2097 2098
	/* Initialize current values. */
	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;
L
Linus Torvalds 已提交
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109
	pkt_dev->nflows = 0;
}

static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
{
	__u64 start;
	__u64 now;

	start = now = getCurUs();
	printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
	while (now < spin_until_us) {
2110
		/* TODO: optimize sleeping behavior */
L
Luiz Capitulino 已提交
2111
		if (spin_until_us - now > jiffies_to_usecs(1) + 1)
2112 2113
			schedule_timeout_interruptible(1);
		else if (spin_until_us - now > 100) {
L
Linus Torvalds 已提交
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
			do_softirq();
			if (!pkt_dev->running)
				return;
			if (need_resched())
				schedule();
		}

		now = getCurUs();
	}

	pkt_dev->idle_acc += now - start;
}

2127 2128
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
{
J
Jamal Hadi Salim 已提交
2129
	pkt_dev->pkt_overhead = 0;
2130 2131 2132 2133 2134
	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);
}

2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
static inline int f_seen(struct pktgen_dev *pkt_dev, int flow)
{

	if (pkt_dev->flows[flow].flags & F_INIT)
		return 1;
	else
		return 0;
}

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;
			pkt_dev->curfl += 1;
			if (pkt_dev->curfl >= pkt_dev->cflows)
				pkt_dev->curfl = 0; /*reset */
		}
	} else {
		flow = random32() % pkt_dev->cflows;

		if (pkt_dev->flows[flow].count > pkt_dev->lflow)
			pkt_dev->flows[flow].count = 0;
	}

	return pkt_dev->curfl;
}

J
Jamal Hadi Salim 已提交
2166 2167 2168 2169 2170

#ifdef CONFIG_XFRM
/* If there was already an IPSEC SA, we keep it as is, else
 * we go look for it ...
*/
2171
static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
J
Jamal Hadi Salim 已提交
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189
{
	struct xfrm_state *x = pkt_dev->flows[flow].x;
	if (!x) {
		/*slow path: we dont already have xfrm_state*/
		x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr,
					(xfrm_address_t *)&pkt_dev->cur_saddr,
					AF_INET,
					pkt_dev->ipsmode,
					pkt_dev->ipsproto, 0);
		if (x) {
			pkt_dev->flows[flow].x = x;
			set_pkt_overhead(pkt_dev);
			pkt_dev->pkt_overhead+=x->props.header_len;
		}

	}
}
#endif
L
Linus Torvalds 已提交
2190 2191 2192
/* Increment/randomize headers according to flags and current values
 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
 */
L
Luiz Capitulino 已提交
2193 2194 2195 2196 2197
static void mod_cur_headers(struct pktgen_dev *pkt_dev)
{
	__u32 imn;
	__u32 imx;
	int flow = 0;
L
Linus Torvalds 已提交
2198

2199 2200
	if (pkt_dev->cflows)
		flow = f_pick(pkt_dev);
L
Linus Torvalds 已提交
2201 2202

	/*  Deal with source MAC */
L
Luiz Capitulino 已提交
2203 2204 2205 2206 2207
	if (pkt_dev->src_mac_count > 1) {
		__u32 mc;
		__u32 tmp;

		if (pkt_dev->flags & F_MACSRC_RND)
S
Stephen Hemminger 已提交
2208
			mc = random32() % pkt_dev->src_mac_count;
L
Luiz Capitulino 已提交
2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233
		else {
			mc = pkt_dev->cur_src_mac_offset++;
			if (pkt_dev->cur_src_mac_offset >
			    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)
S
Stephen Hemminger 已提交
2234
			mc = random32() % pkt_dev->dst_mac_count;
L
Luiz Capitulino 已提交
2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255

		else {
			mc = pkt_dev->cur_dst_mac_offset++;
			if (pkt_dev->cur_dst_mac_offset >
			    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;
	}

2256 2257
	if (pkt_dev->flags & F_MPLS_RND) {
		unsigned i;
2258
		for (i = 0; i < pkt_dev->nr_labels; i++)
2259 2260
			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
S
Stephen Hemminger 已提交
2261
					     ((__force __be32)random32() &
2262 2263 2264
						      htonl(0x000fffff));
	}

F
Francesco Fondelli 已提交
2265
	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
S
Stephen Hemminger 已提交
2266
		pkt_dev->vlan_id = random32() & (4096-1);
F
Francesco Fondelli 已提交
2267 2268 2269
	}

	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
S
Stephen Hemminger 已提交
2270
		pkt_dev->svlan_id = random32() & (4096 - 1);
F
Francesco Fondelli 已提交
2271 2272
	}

L
Luiz Capitulino 已提交
2273 2274
	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
		if (pkt_dev->flags & F_UDPSRC_RND)
S
Stephen Hemminger 已提交
2275 2276 2277
			pkt_dev->cur_udp_src = random32() %
				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
				+ pkt_dev->udp_src_min;
L
Luiz Capitulino 已提交
2278 2279

		else {
L
Linus Torvalds 已提交
2280 2281 2282
			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;
L
Luiz Capitulino 已提交
2283 2284 2285 2286 2287
		}
	}

	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
		if (pkt_dev->flags & F_UDPDST_RND) {
S
Stephen Hemminger 已提交
2288 2289 2290
			pkt_dev->cur_udp_dst = random32() %
				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
				+ pkt_dev->udp_dst_min;
L
Luiz Capitulino 已提交
2291
		} else {
L
Linus Torvalds 已提交
2292
			pkt_dev->cur_udp_dst++;
L
Luiz Capitulino 已提交
2293
			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
L
Linus Torvalds 已提交
2294
				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
L
Luiz Capitulino 已提交
2295 2296
		}
	}
L
Linus Torvalds 已提交
2297 2298 2299

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

L
Luiz Capitulino 已提交
2300 2301 2302
		if ((imn = ntohl(pkt_dev->saddr_min)) < (imx =
							 ntohl(pkt_dev->
							       saddr_max))) {
L
Linus Torvalds 已提交
2303
			__u32 t;
L
Luiz Capitulino 已提交
2304
			if (pkt_dev->flags & F_IPSRC_RND)
S
Stephen Hemminger 已提交
2305
				t = random32() % (imx - imn) + imn;
L
Linus Torvalds 已提交
2306 2307 2308 2309 2310 2311 2312 2313 2314
			else {
				t = ntohl(pkt_dev->cur_saddr);
				t++;
				if (t > imx) {
					t = imn;
				}
			}
			pkt_dev->cur_saddr = htonl(t);
		}
L
Luiz Capitulino 已提交
2315

2316
		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
L
Linus Torvalds 已提交
2317 2318
			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
		} else {
A
Al Viro 已提交
2319 2320 2321
			imn = ntohl(pkt_dev->daddr_min);
			imx = ntohl(pkt_dev->daddr_max);
			if (imn < imx) {
L
Linus Torvalds 已提交
2322
				__u32 t;
A
Al Viro 已提交
2323
				__be32 s;
L
Linus Torvalds 已提交
2324 2325
				if (pkt_dev->flags & F_IPDST_RND) {

S
Stephen Hemminger 已提交
2326
					t = random32() % (imx - imn) + imn;
A
Al Viro 已提交
2327
					s = htonl(t);
L
Linus Torvalds 已提交
2328

A
Al Viro 已提交
2329 2330 2331
					while (LOOPBACK(s) || MULTICAST(s)
					       || BADCLASS(s) || ZERONET(s)
					       || LOCAL_MCAST(s)) {
S
Stephen Hemminger 已提交
2332
						t = random32() % (imx - imn) + imn;
A
Al Viro 已提交
2333
						s = htonl(t);
L
Linus Torvalds 已提交
2334
					}
A
Al Viro 已提交
2335 2336
					pkt_dev->cur_daddr = s;
				} else {
L
Linus Torvalds 已提交
2337 2338 2339 2340 2341 2342 2343 2344
					t = ntohl(pkt_dev->cur_daddr);
					t++;
					if (t > imx) {
						t = imn;
					}
					pkt_dev->cur_daddr = htonl(t);
				}
			}
L
Luiz Capitulino 已提交
2345
			if (pkt_dev->cflows) {
2346
				pkt_dev->flows[flow].flags |= F_INIT;
L
Luiz Capitulino 已提交
2347 2348
				pkt_dev->flows[flow].cur_daddr =
				    pkt_dev->cur_daddr;
J
Jamal Hadi Salim 已提交
2349 2350 2351 2352
#ifdef CONFIG_XFRM
				if (pkt_dev->flags & F_IPSEC_ON)
					get_ipsec_sa(pkt_dev, flow);
#endif
L
Linus Torvalds 已提交
2353 2354 2355
				pkt_dev->nflows++;
			}
		}
L
Luiz Capitulino 已提交
2356 2357 2358 2359 2360 2361
	} else {		/* IPV6 * */

		if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 &&
		    pkt_dev->min_in6_daddr.s6_addr32[1] == 0 &&
		    pkt_dev->min_in6_daddr.s6_addr32[2] == 0 &&
		    pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ;
L
Linus Torvalds 已提交
2362 2363 2364 2365 2366
		else {
			int i;

			/* Only random destinations yet */

L
Luiz Capitulino 已提交
2367
			for (i = 0; i < 4; i++) {
L
Linus Torvalds 已提交
2368
				pkt_dev->cur_in6_daddr.s6_addr32[i] =
S
Stephen Hemminger 已提交
2369
				    (((__force __be32)random32() |
L
Luiz Capitulino 已提交
2370 2371
				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
				     pkt_dev->max_in6_daddr.s6_addr32[i]);
L
Linus Torvalds 已提交
2372
			}
L
Luiz Capitulino 已提交
2373
		}
L
Linus Torvalds 已提交
2374 2375
	}

L
Luiz Capitulino 已提交
2376 2377 2378
	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
		__u32 t;
		if (pkt_dev->flags & F_TXSIZE_RND) {
S
Stephen Hemminger 已提交
2379 2380 2381
			t = random32() %
				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
				+ pkt_dev->min_pkt_size;
L
Luiz Capitulino 已提交
2382
		} else {
L
Linus Torvalds 已提交
2383
			t = pkt_dev->cur_pkt_size + 1;
L
Luiz Capitulino 已提交
2384
			if (t > pkt_dev->max_pkt_size)
L
Linus Torvalds 已提交
2385
				t = pkt_dev->min_pkt_size;
L
Luiz Capitulino 已提交
2386 2387 2388
		}
		pkt_dev->cur_pkt_size = t;
	}
L
Linus Torvalds 已提交
2389 2390 2391 2392

	pkt_dev->flows[flow].count++;
}

J
Jamal Hadi Salim 已提交
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454

#ifdef CONFIG_XFRM
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;
	struct iphdr *iph;

	if (!x)
		return 0;
	/* XXX: we dont support tunnel mode for now until
	 * we resolve the dst issue */
	if (x->props.mode != XFRM_MODE_TRANSPORT)
		return 0;

	spin_lock(&x->lock);
	iph = ip_hdr(skb);

	err = x->mode->output(x, skb);
	if (err)
		goto error;
	err = x->type->output(x, skb);
	if (err)
		goto error;

	x->curlft.bytes +=skb->len;
	x->curlft.packets++;
	spin_unlock(&x->lock);

error:
	spin_unlock(&x->lock);
	return err;
}

static inline void free_SAs(struct pktgen_dev *pkt_dev)
{
	if (pkt_dev->cflows) {
		/* let go of the SAs if we have them */
		int i = 0;
		for (;  i < pkt_dev->nflows; i++){
			struct xfrm_state *x = pkt_dev->flows[i].x;
			if (x) {
				xfrm_state_put(x);
				pkt_dev->flows[i].x = NULL;
			}
		}
	}
}

static inline int process_ipsec(struct pktgen_dev *pkt_dev,
			      struct sk_buff *skb, __be16 protocol)
{
	if (pkt_dev->flags & F_IPSEC_ON) {
		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
		int nhead = 0;
		if (x) {
			int ret;
			__u8 *eth;
			nhead = x->props.header_len - skb_headroom(skb);
			if (nhead >0) {
				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
				if (ret < 0) {
2455 2456
					printk(KERN_ERR "Error expanding "
					       "ipsec packet %d\n",ret);
J
Jamal Hadi Salim 已提交
2457 2458 2459 2460 2461 2462 2463 2464
					return 0;
				}
			}

			/* ipsec is not expecting ll header */
			skb_pull(skb, ETH_HLEN);
			ret = pktgen_output_ipsec(skb, pkt_dev);
			if (ret) {
2465 2466
				printk(KERN_ERR "Error creating ipsec "
				       "packet %d\n",ret);
J
Jamal Hadi Salim 已提交
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479
				kfree_skb(skb);
				return 0;
			}
			/* restore ll */
			eth = (__u8 *) skb_push(skb, ETH_HLEN);
			memcpy(eth, pkt_dev->hh, 12);
			*(u16 *) & eth[12] = protocol;
		}
	}
	return 1;
}
#endif

2480 2481 2482
static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
	unsigned i;
2483
	for (i = 0; i < pkt_dev->nr_labels; i++) {
2484 2485 2486 2487 2488 2489
		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
	}
	mpls--;
	*mpls |= MPLS_STACK_BOTTOM;
}

A
Al Viro 已提交
2490 2491 2492 2493 2494 2495
static inline __be16 build_tci(unsigned int id, unsigned int cfi,
			       unsigned int prio)
{
	return htons(id | (cfi << 12) | (prio << 13));
}

L
Luiz Capitulino 已提交
2496 2497
static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
					struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
2498 2499 2500 2501 2502 2503
{
	struct sk_buff *skb = NULL;
	__u8 *eth;
	struct udphdr *udph;
	int datalen, iplen;
	struct iphdr *iph;
L
Luiz Capitulino 已提交
2504
	struct pktgen_hdr *pgh = NULL;
2505
	__be16 protocol = htons(ETH_P_IP);
2506
	__be32 *mpls;
F
Francesco Fondelli 已提交
2507 2508 2509 2510 2511
	__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 */

2512 2513

	if (pkt_dev->nr_labels)
2514
		protocol = htons(ETH_P_MPLS_UC);
L
Luiz Capitulino 已提交
2515

F
Francesco Fondelli 已提交
2516
	if (pkt_dev->vlan_id != 0xffff)
2517
		protocol = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2518

2519 2520 2521 2522 2523
	/* Update any of the values, used when we're incrementing various
	 * fields.
	 */
	mod_cur_headers(pkt_dev);

2524
	datalen = (odev->hard_header_len + 16) & ~0xf;
2525
	skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
2526
			pkt_dev->pkt_overhead, GFP_ATOMIC);
L
Linus Torvalds 已提交
2527 2528 2529 2530 2531
	if (!skb) {
		sprintf(pkt_dev->result, "No memory");
		return NULL;
	}

2532
	skb_reserve(skb, datalen);
L
Linus Torvalds 已提交
2533 2534 2535

	/*  Reserve for ethernet and IP header  */
	eth = (__u8 *) skb_push(skb, 14);
2536 2537 2538
	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
	if (pkt_dev->nr_labels)
		mpls_push(mpls, pkt_dev);
F
Francesco Fondelli 已提交
2539 2540

	if (pkt_dev->vlan_id != 0xffff) {
2541
		if (pkt_dev->svlan_id != 0xffff) {
F
Francesco Fondelli 已提交
2542
			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2543 2544 2545
			*svlan_tci = build_tci(pkt_dev->svlan_id,
					       pkt_dev->svlan_cfi,
					       pkt_dev->svlan_p);
F
Francesco Fondelli 已提交
2546
			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2547
			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2548 2549
		}
		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2550 2551 2552
		*vlan_tci = build_tci(pkt_dev->vlan_id,
				      pkt_dev->vlan_cfi,
				      pkt_dev->vlan_p);
F
Francesco Fondelli 已提交
2553
		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2554
		*vlan_encapsulated_proto = htons(ETH_P_IP);
F
Francesco Fondelli 已提交
2555 2556
	}

2557
	skb->network_header = skb->tail;
2558
	skb->transport_header = skb->network_header + sizeof(struct iphdr);
2559 2560 2561 2562
	skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));

	iph = ip_hdr(skb);
	udph = udp_hdr(skb);
L
Linus Torvalds 已提交
2563 2564

	memcpy(eth, pkt_dev->hh, 12);
A
Al Viro 已提交
2565
	*(__be16 *) & eth[12] = protocol;
L
Linus Torvalds 已提交
2566

2567 2568
	/* Eth + IPh + UDPh + mpls */
	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
2569
		  pkt_dev->pkt_overhead;
L
Luiz Capitulino 已提交
2570
	if (datalen < sizeof(struct pktgen_hdr))
L
Linus Torvalds 已提交
2571
		datalen = sizeof(struct pktgen_hdr);
L
Luiz Capitulino 已提交
2572

L
Linus Torvalds 已提交
2573 2574
	udph->source = htons(pkt_dev->cur_udp_src);
	udph->dest = htons(pkt_dev->cur_udp_dst);
L
Luiz Capitulino 已提交
2575 2576
	udph->len = htons(datalen + 8);	/* DATA + udphdr */
	udph->check = 0;	/* No checksum */
L
Linus Torvalds 已提交
2577 2578 2579 2580

	iph->ihl = 5;
	iph->version = 4;
	iph->ttl = 32;
F
Francesco Fondelli 已提交
2581
	iph->tos = pkt_dev->tos;
L
Luiz Capitulino 已提交
2582
	iph->protocol = IPPROTO_UDP;	/* UDP */
L
Linus Torvalds 已提交
2583 2584 2585 2586 2587 2588
	iph->saddr = pkt_dev->cur_saddr;
	iph->daddr = pkt_dev->cur_daddr;
	iph->frag_off = 0;
	iplen = 20 + 8 + datalen;
	iph->tot_len = htons(iplen);
	iph->check = 0;
L
Luiz Capitulino 已提交
2589
	iph->check = ip_fast_csum((void *)iph, iph->ihl);
2590
	skb->protocol = protocol;
2591
	skb->mac_header = (skb->network_header - ETH_HLEN -
2592
			   pkt_dev->pkt_overhead);
L
Linus Torvalds 已提交
2593 2594 2595
	skb->dev = odev;
	skb->pkt_type = PACKET_HOST;

L
Luiz Capitulino 已提交
2596 2597
	if (pkt_dev->nfrags <= 0)
		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
L
Linus Torvalds 已提交
2598 2599 2600 2601
	else {
		int frags = pkt_dev->nfrags;
		int i;

L
Luiz Capitulino 已提交
2602 2603
		pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);

L
Linus Torvalds 已提交
2604 2605
		if (frags > MAX_SKB_FRAGS)
			frags = MAX_SKB_FRAGS;
L
Luiz Capitulino 已提交
2606 2607 2608
		if (datalen > frags * PAGE_SIZE) {
			skb_put(skb, datalen - frags * PAGE_SIZE);
			datalen = frags * PAGE_SIZE;
L
Linus Torvalds 已提交
2609 2610 2611 2612 2613 2614 2615 2616
		}

		i = 0;
		while (datalen > 0) {
			struct page *page = alloc_pages(GFP_KERNEL, 0);
			skb_shinfo(skb)->frags[i].page = page;
			skb_shinfo(skb)->frags[i].page_offset = 0;
			skb_shinfo(skb)->frags[i].size =
L
Luiz Capitulino 已提交
2617
			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
L
Linus Torvalds 已提交
2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636
			datalen -= skb_shinfo(skb)->frags[i].size;
			skb->len += skb_shinfo(skb)->frags[i].size;
			skb->data_len += skb_shinfo(skb)->frags[i].size;
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}

		while (i < frags) {
			int rem;

			if (i == 0)
				break;

			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
			if (rem == 0)
				break;

			skb_shinfo(skb)->frags[i - 1].size -= rem;

L
Luiz Capitulino 已提交
2637 2638
			skb_shinfo(skb)->frags[i] =
			    skb_shinfo(skb)->frags[i - 1];
L
Linus Torvalds 已提交
2639
			get_page(skb_shinfo(skb)->frags[i].page);
L
Luiz Capitulino 已提交
2640 2641 2642 2643
			skb_shinfo(skb)->frags[i].page =
			    skb_shinfo(skb)->frags[i - 1].page;
			skb_shinfo(skb)->frags[i].page_offset +=
			    skb_shinfo(skb)->frags[i - 1].size;
L
Linus Torvalds 已提交
2644 2645 2646 2647 2648 2649
			skb_shinfo(skb)->frags[i].size = rem;
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}
	}

L
Luiz Capitulino 已提交
2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661
	/* Stamp the time, and sequence number, convert them to network byte order */

	if (pgh) {
		struct timeval timestamp;

		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
		pgh->seq_num = htonl(pkt_dev->seq_num);

		do_gettimeofday(&timestamp);
		pgh->tv_sec = htonl(timestamp.tv_sec);
		pgh->tv_usec = htonl(timestamp.tv_usec);
	}
L
Linus Torvalds 已提交
2662

J
Jamal Hadi Salim 已提交
2663 2664 2665 2666 2667
#ifdef CONFIG_XFRM
	if (!process_ipsec(pkt_dev, skb, protocol))
		return NULL;
#endif

L
Linus Torvalds 已提交
2668 2669 2670 2671
	return skb;
}

/*
2672
 * scan_ip6, fmt_ip taken from dietlibc-0.21
L
Linus Torvalds 已提交
2673 2674
 * Author Felix von Leitner <felix-dietlibc@fefe.de>
 *
2675
 * Slightly modified for kernel.
L
Linus Torvalds 已提交
2676 2677 2678 2679
 * Should be candidate for net/ipv4/utils.c
 * --ro
 */

L
Luiz Capitulino 已提交
2680
static unsigned int scan_ip6(const char *s, char ip[16])
L
Linus Torvalds 已提交
2681 2682
{
	unsigned int i;
L
Luiz Capitulino 已提交
2683
	unsigned int len = 0;
L
Linus Torvalds 已提交
2684 2685
	unsigned long u;
	char suffix[16];
L
Luiz Capitulino 已提交
2686 2687
	unsigned int prefixlen = 0;
	unsigned int suffixlen = 0;
A
Al Viro 已提交
2688
	__be32 tmp;
L
Linus Torvalds 已提交
2689

L
Luiz Capitulino 已提交
2690 2691
	for (i = 0; i < 16; i++)
		ip[i] = 0;
L
Linus Torvalds 已提交
2692 2693 2694 2695

	for (;;) {
		if (*s == ':') {
			len++;
L
Luiz Capitulino 已提交
2696 2697
			if (s[1] == ':') {	/* Found "::", skip to part 2 */
				s += 2;
L
Linus Torvalds 已提交
2698 2699 2700 2701 2702 2703 2704
				len++;
				break;
			}
			s++;
		}
		{
			char *tmp;
L
Luiz Capitulino 已提交
2705 2706
			u = simple_strtoul(s, &tmp, 16);
			i = tmp - s;
L
Linus Torvalds 已提交
2707 2708
		}

L
Luiz Capitulino 已提交
2709 2710 2711
		if (!i)
			return 0;
		if (prefixlen == 12 && s[i] == '.') {
L
Linus Torvalds 已提交
2712 2713 2714 2715

			/* the last 4 bytes may be written as IPv4 address */

			tmp = in_aton(s);
L
Luiz Capitulino 已提交
2716 2717
			memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp));
			return i + len;
L
Linus Torvalds 已提交
2718 2719 2720
		}
		ip[prefixlen++] = (u >> 8);
		ip[prefixlen++] = (u & 255);
L
Luiz Capitulino 已提交
2721 2722 2723
		s += i;
		len += i;
		if (prefixlen == 16)
L
Linus Torvalds 已提交
2724 2725 2726 2727 2728 2729
			return len;
	}

/* part 2, after "::" */
	for (;;) {
		if (*s == ':') {
L
Luiz Capitulino 已提交
2730
			if (suffixlen == 0)
L
Linus Torvalds 已提交
2731 2732 2733
				break;
			s++;
			len++;
L
Luiz Capitulino 已提交
2734
		} else if (suffixlen != 0)
L
Linus Torvalds 已提交
2735 2736 2737
			break;
		{
			char *tmp;
L
Luiz Capitulino 已提交
2738 2739
			u = simple_strtol(s, &tmp, 16);
			i = tmp - s;
L
Linus Torvalds 已提交
2740 2741
		}
		if (!i) {
L
Luiz Capitulino 已提交
2742 2743
			if (*s)
				len--;
L
Linus Torvalds 已提交
2744 2745
			break;
		}
L
Luiz Capitulino 已提交
2746
		if (suffixlen + prefixlen <= 12 && s[i] == '.') {
L
Linus Torvalds 已提交
2747
			tmp = in_aton(s);
L
Luiz Capitulino 已提交
2748 2749 2750 2751
			memcpy((struct in_addr *)(suffix + suffixlen), &tmp,
			       sizeof(tmp));
			suffixlen += 4;
			len += strlen(s);
L
Linus Torvalds 已提交
2752 2753 2754 2755
			break;
		}
		suffix[suffixlen++] = (u >> 8);
		suffix[suffixlen++] = (u & 255);
L
Luiz Capitulino 已提交
2756 2757 2758
		s += i;
		len += i;
		if (prefixlen + suffixlen == 16)
L
Linus Torvalds 已提交
2759 2760
			break;
	}
L
Luiz Capitulino 已提交
2761 2762
	for (i = 0; i < suffixlen; i++)
		ip[16 - suffixlen + i] = suffix[i];
L
Linus Torvalds 已提交
2763 2764 2765
	return len;
}

L
Luiz Capitulino 已提交
2766 2767 2768
static char tohex(char hexdigit)
{
	return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
L
Linus Torvalds 已提交
2769 2770
}

L
Luiz Capitulino 已提交
2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784
static int fmt_xlong(char *s, unsigned int i)
{
	char *bak = s;
	*s = tohex((i >> 12) & 0xf);
	if (s != bak || *s != '0')
		++s;
	*s = tohex((i >> 8) & 0xf);
	if (s != bak || *s != '0')
		++s;
	*s = tohex((i >> 4) & 0xf);
	if (s != bak || *s != '0')
		++s;
	*s = tohex(i & 0xf);
	return s - bak + 1;
L
Linus Torvalds 已提交
2785 2786
}

L
Luiz Capitulino 已提交
2787 2788
static unsigned int fmt_ip6(char *s, const char ip[16])
{
L
Linus Torvalds 已提交
2789 2790 2791 2792 2793 2794
	unsigned int len;
	unsigned int i;
	unsigned int temp;
	unsigned int compressing;
	int j;

L
Luiz Capitulino 已提交
2795 2796 2797
	len = 0;
	compressing = 0;
	for (j = 0; j < 16; j += 2) {
L
Linus Torvalds 已提交
2798 2799

#ifdef V4MAPPEDPREFIX
L
Luiz Capitulino 已提交
2800 2801 2802 2803
		if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
			inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
			temp = strlen(s);
			return len + temp;
L
Linus Torvalds 已提交
2804 2805
		}
#endif
L
Luiz Capitulino 已提交
2806 2807
		temp = ((unsigned long)(unsigned char)ip[j] << 8) +
		    (unsigned long)(unsigned char)ip[j + 1];
L
Linus Torvalds 已提交
2808 2809
		if (temp == 0) {
			if (!compressing) {
L
Luiz Capitulino 已提交
2810 2811 2812 2813
				compressing = 1;
				if (j == 0) {
					*s++ = ':';
					++len;
L
Linus Torvalds 已提交
2814 2815 2816 2817
				}
			}
		} else {
			if (compressing) {
L
Luiz Capitulino 已提交
2818 2819 2820
				compressing = 0;
				*s++ = ':';
				++len;
L
Linus Torvalds 已提交
2821
			}
L
Luiz Capitulino 已提交
2822 2823 2824 2825
			i = fmt_xlong(s, temp);
			len += i;
			s += i;
			if (j < 14) {
L
Linus Torvalds 已提交
2826 2827 2828 2829 2830 2831
				*s++ = ':';
				++len;
			}
		}
	}
	if (compressing) {
L
Luiz Capitulino 已提交
2832 2833
		*s++ = ':';
		++len;
L
Linus Torvalds 已提交
2834
	}
L
Luiz Capitulino 已提交
2835
	*s = 0;
L
Linus Torvalds 已提交
2836 2837 2838
	return len;
}

L
Luiz Capitulino 已提交
2839 2840
static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
					struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
2841 2842 2843 2844 2845 2846
{
	struct sk_buff *skb = NULL;
	__u8 *eth;
	struct udphdr *udph;
	int datalen;
	struct ipv6hdr *iph;
L
Luiz Capitulino 已提交
2847
	struct pktgen_hdr *pgh = NULL;
2848
	__be16 protocol = htons(ETH_P_IPV6);
2849
	__be32 *mpls;
F
Francesco Fondelli 已提交
2850 2851 2852 2853
	__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 */
2854 2855

	if (pkt_dev->nr_labels)
2856
		protocol = htons(ETH_P_MPLS_UC);
2857

F
Francesco Fondelli 已提交
2858
	if (pkt_dev->vlan_id != 0xffff)
2859
		protocol = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2860

2861 2862 2863 2864 2865
	/* Update any of the values, used when we're incrementing various
	 * fields.
	 */
	mod_cur_headers(pkt_dev);

2866
	skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
2867
			pkt_dev->pkt_overhead, GFP_ATOMIC);
L
Linus Torvalds 已提交
2868 2869 2870 2871 2872 2873 2874 2875 2876
	if (!skb) {
		sprintf(pkt_dev->result, "No memory");
		return NULL;
	}

	skb_reserve(skb, 16);

	/*  Reserve for ethernet and IP header  */
	eth = (__u8 *) skb_push(skb, 14);
2877 2878 2879
	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
	if (pkt_dev->nr_labels)
		mpls_push(mpls, pkt_dev);
F
Francesco Fondelli 已提交
2880 2881

	if (pkt_dev->vlan_id != 0xffff) {
2882
		if (pkt_dev->svlan_id != 0xffff) {
F
Francesco Fondelli 已提交
2883
			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2884 2885 2886
			*svlan_tci = build_tci(pkt_dev->svlan_id,
					       pkt_dev->svlan_cfi,
					       pkt_dev->svlan_p);
F
Francesco Fondelli 已提交
2887
			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2888
			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2889 2890
		}
		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2891 2892 2893
		*vlan_tci = build_tci(pkt_dev->vlan_id,
				      pkt_dev->vlan_cfi,
				      pkt_dev->vlan_p);
F
Francesco Fondelli 已提交
2894
		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2895
		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
F
Francesco Fondelli 已提交
2896 2897
	}

2898
	skb->network_header = skb->tail;
2899
	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
2900 2901 2902 2903
	skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));

	iph = ipv6_hdr(skb);
	udph = udp_hdr(skb);
L
Linus Torvalds 已提交
2904 2905

	memcpy(eth, pkt_dev->hh, 12);
A
Al Viro 已提交
2906
	*(__be16 *) & eth[12] = protocol;
2907

2908 2909 2910
	/* Eth + IPh + UDPh + mpls */
	datalen = pkt_dev->cur_pkt_size - 14 -
		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
2911
		  pkt_dev->pkt_overhead;
L
Linus Torvalds 已提交
2912

L
Luiz Capitulino 已提交
2913
	if (datalen < sizeof(struct pktgen_hdr)) {
L
Linus Torvalds 已提交
2914 2915
		datalen = sizeof(struct pktgen_hdr);
		if (net_ratelimit())
L
Luiz Capitulino 已提交
2916 2917
			printk(KERN_INFO "pktgen: increased datalen to %d\n",
			       datalen);
L
Linus Torvalds 已提交
2918 2919 2920 2921
	}

	udph->source = htons(pkt_dev->cur_udp_src);
	udph->dest = htons(pkt_dev->cur_udp_dst);
L
Luiz Capitulino 已提交
2922 2923
	udph->len = htons(datalen + sizeof(struct udphdr));
	udph->check = 0;	/* No checksum */
L
Linus Torvalds 已提交
2924

2925
	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
L
Linus Torvalds 已提交
2926

F
Francesco Fondelli 已提交
2927 2928
	if (pkt_dev->traffic_class) {
		/* Version + traffic class + flow (0) */
A
Al Viro 已提交
2929
		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
F
Francesco Fondelli 已提交
2930 2931
	}

L
Linus Torvalds 已提交
2932 2933 2934 2935 2936 2937 2938 2939
	iph->hop_limit = 32;

	iph->payload_len = htons(sizeof(struct udphdr) + datalen);
	iph->nexthdr = IPPROTO_UDP;

	ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
	ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);

2940
	skb->mac_header = (skb->network_header - ETH_HLEN -
2941
			   pkt_dev->pkt_overhead);
2942
	skb->protocol = protocol;
L
Linus Torvalds 已提交
2943 2944 2945
	skb->dev = odev;
	skb->pkt_type = PACKET_HOST;

L
Luiz Capitulino 已提交
2946 2947
	if (pkt_dev->nfrags <= 0)
		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
L
Linus Torvalds 已提交
2948 2949 2950 2951
	else {
		int frags = pkt_dev->nfrags;
		int i;

L
Luiz Capitulino 已提交
2952 2953
		pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);

L
Linus Torvalds 已提交
2954 2955
		if (frags > MAX_SKB_FRAGS)
			frags = MAX_SKB_FRAGS;
L
Luiz Capitulino 已提交
2956 2957 2958
		if (datalen > frags * PAGE_SIZE) {
			skb_put(skb, datalen - frags * PAGE_SIZE);
			datalen = frags * PAGE_SIZE;
L
Linus Torvalds 已提交
2959 2960 2961 2962 2963 2964 2965 2966
		}

		i = 0;
		while (datalen > 0) {
			struct page *page = alloc_pages(GFP_KERNEL, 0);
			skb_shinfo(skb)->frags[i].page = page;
			skb_shinfo(skb)->frags[i].page_offset = 0;
			skb_shinfo(skb)->frags[i].size =
L
Luiz Capitulino 已提交
2967
			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
L
Linus Torvalds 已提交
2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986
			datalen -= skb_shinfo(skb)->frags[i].size;
			skb->len += skb_shinfo(skb)->frags[i].size;
			skb->data_len += skb_shinfo(skb)->frags[i].size;
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}

		while (i < frags) {
			int rem;

			if (i == 0)
				break;

			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
			if (rem == 0)
				break;

			skb_shinfo(skb)->frags[i - 1].size -= rem;

L
Luiz Capitulino 已提交
2987 2988
			skb_shinfo(skb)->frags[i] =
			    skb_shinfo(skb)->frags[i - 1];
L
Linus Torvalds 已提交
2989
			get_page(skb_shinfo(skb)->frags[i].page);
L
Luiz Capitulino 已提交
2990 2991 2992 2993
			skb_shinfo(skb)->frags[i].page =
			    skb_shinfo(skb)->frags[i - 1].page;
			skb_shinfo(skb)->frags[i].page_offset +=
			    skb_shinfo(skb)->frags[i - 1].size;
L
Linus Torvalds 已提交
2994 2995 2996 2997 2998 2999
			skb_shinfo(skb)->frags[i].size = rem;
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}
	}

L
Luiz Capitulino 已提交
3000
	/* Stamp the time, and sequence number, convert them to network byte order */
L
Linus Torvalds 已提交
3001
	/* should we update cloned packets too ? */
L
Luiz Capitulino 已提交
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011
	if (pgh) {
		struct timeval timestamp;

		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
		pgh->seq_num = htonl(pkt_dev->seq_num);

		do_gettimeofday(&timestamp);
		pgh->tv_sec = htonl(timestamp.tv_sec);
		pgh->tv_usec = htonl(timestamp.tv_usec);
	}
F
Francesco Fondelli 已提交
3012
	/* pkt_dev->seq_num++; FF: you really mean this? */
L
Luiz Capitulino 已提交
3013

L
Linus Torvalds 已提交
3014 3015 3016
	return skb;
}

L
Luiz Capitulino 已提交
3017 3018
static inline struct sk_buff *fill_packet(struct net_device *odev,
					  struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3019
{
L
Luiz Capitulino 已提交
3020
	if (pkt_dev->flags & F_IPV6)
L
Linus Torvalds 已提交
3021 3022 3023 3024 3025
		return fill_packet_ipv6(odev, pkt_dev);
	else
		return fill_packet_ipv4(odev, pkt_dev);
}

L
Luiz Capitulino 已提交
3026
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3027
{
L
Luiz Capitulino 已提交
3028 3029
	pkt_dev->seq_num = 1;
	pkt_dev->idle_acc = 0;
L
Linus Torvalds 已提交
3030
	pkt_dev->sofar = 0;
L
Luiz Capitulino 已提交
3031 3032
	pkt_dev->tx_bytes = 0;
	pkt_dev->errors = 0;
L
Linus Torvalds 已提交
3033 3034 3035 3036 3037 3038
}

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

static void pktgen_run(struct pktgen_thread *t)
{
3039
	struct pktgen_dev *pkt_dev;
L
Linus Torvalds 已提交
3040 3041
	int started = 0;

S
Stephen Hemminger 已提交
3042
	pr_debug("pktgen: entering pktgen_run. %p\n", t);
L
Linus Torvalds 已提交
3043 3044

	if_lock(t);
3045
	list_for_each_entry(pkt_dev, &t->if_list, list) {
L
Linus Torvalds 已提交
3046 3047 3048 3049 3050 3051

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

L
Luiz Capitulino 已提交
3052
		if (pkt_dev->odev) {
L
Linus Torvalds 已提交
3053
			pktgen_clear_counters(pkt_dev);
L
Luiz Capitulino 已提交
3054
			pkt_dev->running = 1;	/* Cranke yeself! */
L
Linus Torvalds 已提交
3055 3056
			pkt_dev->skb = NULL;
			pkt_dev->started_at = getCurUs();
L
Luiz Capitulino 已提交
3057
			pkt_dev->next_tx_us = getCurUs();	/* Transmit immediately */
L
Linus Torvalds 已提交
3058
			pkt_dev->next_tx_ns = 0;
3059
			set_pkt_overhead(pkt_dev);
L
Luiz Capitulino 已提交
3060

L
Linus Torvalds 已提交
3061 3062
			strcpy(pkt_dev->result, "Starting");
			started++;
L
Luiz Capitulino 已提交
3063
		} else
L
Linus Torvalds 已提交
3064 3065 3066
			strcpy(pkt_dev->result, "Error starting");
	}
	if_unlock(t);
L
Luiz Capitulino 已提交
3067 3068
	if (started)
		t->control &= ~(T_STOP);
L
Linus Torvalds 已提交
3069 3070 3071 3072
}

static void pktgen_stop_all_threads_ifs(void)
{
3073
	struct pktgen_thread *t;
L
Linus Torvalds 已提交
3074

S
Stephen Hemminger 已提交
3075
	pr_debug("pktgen: entering pktgen_stop_all_threads_ifs.\n");
L
Linus Torvalds 已提交
3076

3077
	mutex_lock(&pktgen_thread_lock);
3078 3079

	list_for_each_entry(t, &pktgen_threads, th_list)
3080
		t->control |= T_STOP;
3081

3082
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3083 3084
}

L
Luiz Capitulino 已提交
3085
static int thread_is_running(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3086
{
3087
	struct pktgen_dev *pkt_dev;
L
Luiz Capitulino 已提交
3088
	int res = 0;
L
Linus Torvalds 已提交
3089

3090 3091
	list_for_each_entry(pkt_dev, &t->if_list, list)
		if (pkt_dev->running) {
L
Linus Torvalds 已提交
3092 3093 3094
			res = 1;
			break;
		}
L
Luiz Capitulino 已提交
3095
	return res;
L
Linus Torvalds 已提交
3096 3097
}

L
Luiz Capitulino 已提交
3098
static int pktgen_wait_thread_run(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3099
{
L
Luiz Capitulino 已提交
3100
	if_lock(t);
L
Linus Torvalds 已提交
3101

L
Luiz Capitulino 已提交
3102
	while (thread_is_running(t)) {
L
Linus Torvalds 已提交
3103

L
Luiz Capitulino 已提交
3104
		if_unlock(t);
L
Linus Torvalds 已提交
3105

L
Luiz Capitulino 已提交
3106
		msleep_interruptible(100);
L
Linus Torvalds 已提交
3107

L
Luiz Capitulino 已提交
3108 3109 3110 3111 3112 3113 3114 3115
		if (signal_pending(current))
			goto signal;
		if_lock(t);
	}
	if_unlock(t);
	return 1;
signal:
	return 0;
L
Linus Torvalds 已提交
3116 3117 3118 3119
}

static int pktgen_wait_all_threads_run(void)
{
3120
	struct pktgen_thread *t;
L
Linus Torvalds 已提交
3121
	int sig = 1;
L
Luiz Capitulino 已提交
3122

3123
	mutex_lock(&pktgen_thread_lock);
3124 3125

	list_for_each_entry(t, &pktgen_threads, th_list) {
L
Linus Torvalds 已提交
3126
		sig = pktgen_wait_thread_run(t);
L
Luiz Capitulino 已提交
3127 3128
		if (sig == 0)
			break;
L
Linus Torvalds 已提交
3129
	}
3130 3131 3132

	if (sig == 0)
		list_for_each_entry(t, &pktgen_threads, th_list)
L
Linus Torvalds 已提交
3133
			t->control |= (T_STOP);
3134

3135
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3136 3137 3138 3139 3140
	return sig;
}

static void pktgen_run_all_threads(void)
{
3141
	struct pktgen_thread *t;
L
Linus Torvalds 已提交
3142

S
Stephen Hemminger 已提交
3143
	pr_debug("pktgen: entering pktgen_run_all_threads.\n");
L
Linus Torvalds 已提交
3144

3145
	mutex_lock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3146

3147
	list_for_each_entry(t, &pktgen_threads, th_list)
L
Linus Torvalds 已提交
3148
		t->control |= (T_RUN);
3149

3150
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3151

L
Luiz Capitulino 已提交
3152 3153
	schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */

L
Linus Torvalds 已提交
3154 3155 3156 3157 3158
	pktgen_wait_all_threads_run();
}

static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
{
L
Luiz Capitulino 已提交
3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190
	__u64 total_us, bps, mbps, pps, idle;
	char *p = pkt_dev->result;

	total_us = pkt_dev->stopped_at - pkt_dev->started_at;

	idle = pkt_dev->idle_acc;

	p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
		     (unsigned long long)total_us,
		     (unsigned long long)(total_us - idle),
		     (unsigned long long)idle,
		     (unsigned long long)pkt_dev->sofar,
		     pkt_dev->cur_pkt_size, nr_frags);

	pps = pkt_dev->sofar * USEC_PER_SEC;

	while ((total_us >> 32) != 0) {
		pps >>= 1;
		total_us >>= 1;
	}

	do_div(pps, total_us);

	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);
L
Linus Torvalds 已提交
3191 3192 3193 3194
}

/* Set stopped-at timer, remove from running list, do counters & statistics */

L
Luiz Capitulino 已提交
3195
static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3196
{
L
Luiz Capitulino 已提交
3197
	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
3198

L
Luiz Capitulino 已提交
3199
	if (!pkt_dev->running) {
3200 3201
		printk(KERN_WARNING "pktgen: interface: %s is already "
		       "stopped\n", pkt_dev->odev->name);
L
Luiz Capitulino 已提交
3202 3203
		return -EINVAL;
	}
L
Linus Torvalds 已提交
3204

L
Luiz Capitulino 已提交
3205 3206
	pkt_dev->stopped_at = getCurUs();
	pkt_dev->running = 0;
L
Linus Torvalds 已提交
3207

3208
	show_results(pkt_dev, nr_frags);
L
Linus Torvalds 已提交
3209

L
Luiz Capitulino 已提交
3210
	return 0;
L
Linus Torvalds 已提交
3211 3212
}

L
Luiz Capitulino 已提交
3213
static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3214
{
3215
	struct pktgen_dev *pkt_dev, *best = NULL;
L
Luiz Capitulino 已提交
3216

L
Linus Torvalds 已提交
3217 3218
	if_lock(t);

3219 3220
	list_for_each_entry(pkt_dev, &t->if_list, list) {
		if (!pkt_dev->running)
L
Luiz Capitulino 已提交
3221 3222
			continue;
		if (best == NULL)
3223 3224 3225
			best = pkt_dev;
		else if (pkt_dev->next_tx_us < best->next_tx_us)
			best = pkt_dev;
L
Linus Torvalds 已提交
3226 3227
	}
	if_unlock(t);
L
Luiz Capitulino 已提交
3228
	return best;
L
Linus Torvalds 已提交
3229 3230
}

L
Luiz Capitulino 已提交
3231 3232
static void pktgen_stop(struct pktgen_thread *t)
{
3233
	struct pktgen_dev *pkt_dev;
L
Linus Torvalds 已提交
3234

S
Stephen Hemminger 已提交
3235
	pr_debug("pktgen: entering pktgen_stop\n");
L
Linus Torvalds 已提交
3236

L
Luiz Capitulino 已提交
3237
	if_lock(t);
L
Linus Torvalds 已提交
3238

3239 3240 3241 3242
	list_for_each_entry(pkt_dev, &t->if_list, list) {
		pktgen_stop_device(pkt_dev);
		if (pkt_dev->skb)
			kfree_skb(pkt_dev->skb);
3243

3244
		pkt_dev->skb = NULL;
3245
	}
L
Linus Torvalds 已提交
3246

L
Luiz Capitulino 已提交
3247
	if_unlock(t);
L
Linus Torvalds 已提交
3248 3249
}

3250 3251 3252 3253 3254 3255
/*
 * one of our devices needs to be removed - find it
 * and remove it
 */
static void pktgen_rem_one_if(struct pktgen_thread *t)
{
3256 3257
	struct list_head *q, *n;
	struct pktgen_dev *cur;
3258

S
Stephen Hemminger 已提交
3259
	pr_debug("pktgen: entering pktgen_rem_one_if\n");
3260 3261 3262

	if_lock(t);

3263 3264
	list_for_each_safe(q, n, &t->if_list) {
		cur = list_entry(q, struct pktgen_dev, list);
3265

L
Luiz Capitulino 已提交
3266 3267
		if (!cur->removal_mark)
			continue;
3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280

		if (cur->skb)
			kfree_skb(cur->skb);
		cur->skb = NULL;

		pktgen_remove_device(t, cur);

		break;
	}

	if_unlock(t);
}

L
Luiz Capitulino 已提交
3281
static void pktgen_rem_all_ifs(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3282
{
3283 3284
	struct list_head *q, *n;
	struct pktgen_dev *cur;
L
Luiz Capitulino 已提交
3285 3286

	/* Remove all devices, free mem */
3287

S
Stephen Hemminger 已提交
3288
	pr_debug("pktgen: entering pktgen_rem_all_ifs\n");
L
Luiz Capitulino 已提交
3289
	if_lock(t);
L
Linus Torvalds 已提交
3290

3291 3292
	list_for_each_safe(q, n, &t->if_list) {
		cur = list_entry(q, struct pktgen_dev, list);
3293 3294 3295 3296 3297

		if (cur->skb)
			kfree_skb(cur->skb);
		cur->skb = NULL;

L
Linus Torvalds 已提交
3298 3299 3300
		pktgen_remove_device(t, cur);
	}

L
Luiz Capitulino 已提交
3301
	if_unlock(t);
L
Linus Torvalds 已提交
3302 3303
}

L
Luiz Capitulino 已提交
3304
static void pktgen_rem_thread(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3305
{
L
Luiz Capitulino 已提交
3306
	/* Remove from the thread list */
L
Linus Torvalds 已提交
3307

3308
	remove_proc_entry(t->tsk->comm, pg_proc_dir);
L
Linus Torvalds 已提交
3309

3310
	mutex_lock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3311

3312 3313
	list_del(&t->th_list);

3314
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3315 3316 3317 3318 3319 3320 3321 3322 3323
}

static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
{
	struct net_device *odev = NULL;
	__u64 idle_start = 0;
	int ret;

	odev = pkt_dev->odev;
L
Luiz Capitulino 已提交
3324

L
Linus Torvalds 已提交
3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
	if (pkt_dev->delay_us || pkt_dev->delay_ns) {
		u64 now;

		now = getCurUs();
		if (now < pkt_dev->next_tx_us)
			spin(pkt_dev, pkt_dev->next_tx_us);

		/* This is max DELAY, this has special meaning of
		 * "never transmit"
		 */
		if (pkt_dev->delay_us == 0x7FFFFFFF) {
			pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us;
			pkt_dev->next_tx_ns = pkt_dev->delay_ns;
			goto out;
		}
	}
L
Luiz Capitulino 已提交
3341

3342
	if ((netif_queue_stopped(odev) ||
R
Robert Olsson 已提交
3343 3344 3345
	     (pkt_dev->skb &&
	      netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) ||
	    need_resched()) {
L
Linus Torvalds 已提交
3346
		idle_start = getCurUs();
L
Luiz Capitulino 已提交
3347

L
Linus Torvalds 已提交
3348 3349
		if (!netif_running(odev)) {
			pktgen_stop_device(pkt_dev);
3350 3351 3352
			if (pkt_dev->skb)
				kfree_skb(pkt_dev->skb);
			pkt_dev->skb = NULL;
L
Linus Torvalds 已提交
3353 3354
			goto out;
		}
L
Luiz Capitulino 已提交
3355
		if (need_resched())
L
Linus Torvalds 已提交
3356
			schedule();
L
Luiz Capitulino 已提交
3357

L
Linus Torvalds 已提交
3358
		pkt_dev->idle_acc += getCurUs() - idle_start;
L
Luiz Capitulino 已提交
3359

3360 3361
		if (netif_queue_stopped(odev) ||
		    netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
L
Luiz Capitulino 已提交
3362
			pkt_dev->next_tx_us = getCurUs();	/* TODO */
L
Linus Torvalds 已提交
3363
			pkt_dev->next_tx_ns = 0;
L
Luiz Capitulino 已提交
3364
			goto out;	/* Try the next interface */
L
Linus Torvalds 已提交
3365 3366
		}
	}
L
Luiz Capitulino 已提交
3367

L
Linus Torvalds 已提交
3368
	if (pkt_dev->last_ok || !pkt_dev->skb) {
L
Luiz Capitulino 已提交
3369 3370
		if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
		    || (!pkt_dev->skb)) {
L
Linus Torvalds 已提交
3371
			/* build a new pkt */
L
Luiz Capitulino 已提交
3372
			if (pkt_dev->skb)
L
Linus Torvalds 已提交
3373
				kfree_skb(pkt_dev->skb);
L
Luiz Capitulino 已提交
3374

L
Linus Torvalds 已提交
3375 3376
			pkt_dev->skb = fill_packet(odev, pkt_dev);
			if (pkt_dev->skb == NULL) {
3377 3378
				printk(KERN_ERR "pktgen: ERROR: couldn't "
				       "allocate skb in fill_packet.\n");
L
Linus Torvalds 已提交
3379
				schedule();
L
Luiz Capitulino 已提交
3380
				pkt_dev->clone_count--;	/* back out increment, OOM */
L
Linus Torvalds 已提交
3381 3382 3383
				goto out;
			}
			pkt_dev->allocated_skbs++;
L
Luiz Capitulino 已提交
3384
			pkt_dev->clone_count = 0;	/* reset counter */
L
Linus Torvalds 已提交
3385 3386
		}
	}
3387

H
Herbert Xu 已提交
3388
	netif_tx_lock_bh(odev);
3389 3390
	if (!netif_queue_stopped(odev) &&
	    !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
L
Linus Torvalds 已提交
3391 3392

		atomic_inc(&(pkt_dev->skb->users));
L
Luiz Capitulino 已提交
3393
	      retry_now:
L
Linus Torvalds 已提交
3394 3395
		ret = odev->hard_start_xmit(pkt_dev->skb, odev);
		if (likely(ret == NETDEV_TX_OK)) {
L
Luiz Capitulino 已提交
3396
			pkt_dev->last_ok = 1;
L
Linus Torvalds 已提交
3397 3398 3399
			pkt_dev->sofar++;
			pkt_dev->seq_num++;
			pkt_dev->tx_bytes += pkt_dev->cur_pkt_size;
L
Luiz Capitulino 已提交
3400 3401

		} else if (ret == NETDEV_TX_LOCKED
L
Linus Torvalds 已提交
3402 3403 3404
			   && (odev->features & NETIF_F_LLTX)) {
			cpu_relax();
			goto retry_now;
L
Luiz Capitulino 已提交
3405 3406
		} else {	/* Retry it next time */

L
Linus Torvalds 已提交
3407
			atomic_dec(&(pkt_dev->skb->users));
L
Luiz Capitulino 已提交
3408

L
Linus Torvalds 已提交
3409 3410
			if (debug && net_ratelimit())
				printk(KERN_INFO "pktgen: Hard xmit error\n");
L
Luiz Capitulino 已提交
3411

L
Linus Torvalds 已提交
3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425
			pkt_dev->errors++;
			pkt_dev->last_ok = 0;
		}

		pkt_dev->next_tx_us = getCurUs();
		pkt_dev->next_tx_ns = 0;

		pkt_dev->next_tx_us += pkt_dev->delay_us;
		pkt_dev->next_tx_ns += pkt_dev->delay_ns;

		if (pkt_dev->next_tx_ns > 1000) {
			pkt_dev->next_tx_us++;
			pkt_dev->next_tx_ns -= 1000;
		}
L
Luiz Capitulino 已提交
3426
	}
L
Linus Torvalds 已提交
3427

L
Luiz Capitulino 已提交
3428 3429 3430
	else {			/* Retry it next time */
		pkt_dev->last_ok = 0;
		pkt_dev->next_tx_us = getCurUs();	/* TODO */
L
Linus Torvalds 已提交
3431
		pkt_dev->next_tx_ns = 0;
L
Luiz Capitulino 已提交
3432
	}
L
Linus Torvalds 已提交
3433

H
Herbert Xu 已提交
3434
	netif_tx_unlock_bh(odev);
L
Luiz Capitulino 已提交
3435

L
Linus Torvalds 已提交
3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447
	/* If pkt_dev->count is zero, then run forever */
	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
		if (atomic_read(&(pkt_dev->skb->users)) != 1) {
			idle_start = getCurUs();
			while (atomic_read(&(pkt_dev->skb->users)) != 1) {
				if (signal_pending(current)) {
					break;
				}
				schedule();
			}
			pkt_dev->idle_acc += getCurUs() - idle_start;
		}
L
Luiz Capitulino 已提交
3448

L
Linus Torvalds 已提交
3449 3450
		/* Done with this */
		pktgen_stop_device(pkt_dev);
3451 3452 3453
		if (pkt_dev->skb)
			kfree_skb(pkt_dev->skb);
		pkt_dev->skb = NULL;
L
Luiz Capitulino 已提交
3454 3455 3456
	}
out:;
}
L
Linus Torvalds 已提交
3457

3458
/*
L
Linus Torvalds 已提交
3459 3460 3461
 * Main loop of the thread goes here
 */

3462
static int pktgen_thread_worker(void *arg)
L
Linus Torvalds 已提交
3463 3464
{
	DEFINE_WAIT(wait);
3465
	struct pktgen_thread *t = arg;
L
Luiz Capitulino 已提交
3466
	struct pktgen_dev *pkt_dev = NULL;
L
Linus Torvalds 已提交
3467 3468
	int cpu = t->cpu;
	u32 max_before_softirq;
L
Luiz Capitulino 已提交
3469
	u32 tx_since_softirq = 0;
L
Linus Torvalds 已提交
3470

3471
	BUG_ON(smp_processor_id() != cpu);
L
Linus Torvalds 已提交
3472 3473 3474

	init_waitqueue_head(&t->queue);

S
Stephen Hemminger 已提交
3475
	pr_debug("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid);
L
Linus Torvalds 已提交
3476 3477 3478

	max_before_softirq = t->max_before_softirq;

3479
	set_current_state(TASK_INTERRUPTIBLE);
L
Luiz Capitulino 已提交
3480

3481 3482
	set_freezable();

3483 3484
	while (!kthread_should_stop()) {
		pkt_dev = next_to_run(t);
L
Linus Torvalds 已提交
3485

3486 3487 3488 3489 3490 3491 3492 3493
		if (!pkt_dev &&
		    (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV))
		    == 0) {
			prepare_to_wait(&(t->queue), &wait,
					TASK_INTERRUPTIBLE);
			schedule_timeout(HZ / 10);
			finish_wait(&(t->queue), &wait);
		}
L
Linus Torvalds 已提交
3494

3495
		__set_current_state(TASK_RUNNING);
L
Luiz Capitulino 已提交
3496 3497

		if (pkt_dev) {
L
Linus Torvalds 已提交
3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514

			pktgen_xmit(pkt_dev);

			/*
			 * We like to stay RUNNING but must also give
			 * others fair share.
			 */

			tx_since_softirq += pkt_dev->last_ok;

			if (tx_since_softirq > max_before_softirq) {
				if (local_softirq_pending())
					do_softirq();
				tx_since_softirq = 0;
			}
		}

L
Luiz Capitulino 已提交
3515
		if (t->control & T_STOP) {
L
Linus Torvalds 已提交
3516 3517 3518 3519
			pktgen_stop(t);
			t->control &= ~(T_STOP);
		}

L
Luiz Capitulino 已提交
3520
		if (t->control & T_RUN) {
L
Linus Torvalds 已提交
3521 3522 3523 3524
			pktgen_run(t);
			t->control &= ~(T_RUN);
		}

L
Luiz Capitulino 已提交
3525
		if (t->control & T_REMDEVALL) {
L
Linus Torvalds 已提交
3526
			pktgen_rem_all_ifs(t);
3527 3528 3529
			t->control &= ~(T_REMDEVALL);
		}

L
Luiz Capitulino 已提交
3530
		if (t->control & T_REMDEV) {
3531
			pktgen_rem_one_if(t);
L
Linus Torvalds 已提交
3532 3533 3534
			t->control &= ~(T_REMDEV);
		}

A
Andrew Morton 已提交
3535 3536
		try_to_freeze();

3537
		set_current_state(TASK_INTERRUPTIBLE);
L
Luiz Capitulino 已提交
3538
	}
L
Linus Torvalds 已提交
3539

S
Stephen Hemminger 已提交
3540
	pr_debug("pktgen: %s stopping all device\n", t->tsk->comm);
L
Luiz Capitulino 已提交
3541
	pktgen_stop(t);
L
Linus Torvalds 已提交
3542

S
Stephen Hemminger 已提交
3543
	pr_debug("pktgen: %s removing all device\n", t->tsk->comm);
L
Luiz Capitulino 已提交
3544
	pktgen_rem_all_ifs(t);
L
Linus Torvalds 已提交
3545

S
Stephen Hemminger 已提交
3546
	pr_debug("pktgen: %s removing thread.\n", t->tsk->comm);
L
Luiz Capitulino 已提交
3547
	pktgen_rem_thread(t);
3548

3549
	return 0;
L
Linus Torvalds 已提交
3550 3551
}

L
Luiz Capitulino 已提交
3552 3553
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
					  const char *ifname)
L
Linus Torvalds 已提交
3554
{
3555
	struct pktgen_dev *p, *pkt_dev = NULL;
L
Luiz Capitulino 已提交
3556 3557
	if_lock(t);

3558
	list_for_each_entry(p, &t->if_list, list)
3559
		if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) {
3560
			pkt_dev = p;
L
Luiz Capitulino 已提交
3561 3562 3563 3564
			break;
		}

	if_unlock(t);
S
Stephen Hemminger 已提交
3565
	pr_debug("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev);
L
Luiz Capitulino 已提交
3566
	return pkt_dev;
L
Linus Torvalds 已提交
3567 3568
}

3569 3570
/*
 * Adds a dev at front of if_list.
L
Linus Torvalds 已提交
3571 3572
 */

L
Luiz Capitulino 已提交
3573 3574
static int add_dev_to_thread(struct pktgen_thread *t,
			     struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3575 3576
{
	int rv = 0;
L
Luiz Capitulino 已提交
3577 3578 3579 3580

	if_lock(t);

	if (pkt_dev->pg_thread) {
3581 3582
		printk(KERN_ERR "pktgen: ERROR: already assigned "
		       "to a thread.\n");
L
Luiz Capitulino 已提交
3583 3584 3585
		rv = -EBUSY;
		goto out;
	}
3586 3587

	list_add(&pkt_dev->list, &t->if_list);
L
Luiz Capitulino 已提交
3588
	pkt_dev->pg_thread = t;
L
Linus Torvalds 已提交
3589 3590
	pkt_dev->running = 0;

L
Luiz Capitulino 已提交
3591 3592 3593
out:
	if_unlock(t);
	return rv;
L
Linus Torvalds 已提交
3594 3595 3596 3597
}

/* Called under thread lock */

L
Luiz Capitulino 已提交
3598
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
L
Linus Torvalds 已提交
3599
{
L
Luiz Capitulino 已提交
3600
	struct pktgen_dev *pkt_dev;
3601
	int err;
L
Luiz Capitulino 已提交
3602

L
Linus Torvalds 已提交
3603 3604
	/* We don't allow a device to be on several threads */

3605 3606
	pkt_dev = __pktgen_NN_threads(ifname, FIND);
	if (pkt_dev) {
3607
		printk(KERN_ERR "pktgen: ERROR: interface already used.\n");
L
Luiz Capitulino 已提交
3608 3609
		return -EBUSY;
	}
3610 3611 3612 3613 3614

	pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL);
	if (!pkt_dev)
		return -ENOMEM;

L
Luiz Capitulino 已提交
3615
	pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state));
3616 3617 3618 3619
	if (pkt_dev->flows == NULL) {
		kfree(pkt_dev);
		return -ENOMEM;
	}
L
Luiz Capitulino 已提交
3620
	memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state));
3621

3622
	pkt_dev->removal_mark = 0;
3623 3624 3625 3626 3627 3628 3629 3630
	pkt_dev->min_pkt_size = ETH_ZLEN;
	pkt_dev->max_pkt_size = ETH_ZLEN;
	pkt_dev->nfrags = 0;
	pkt_dev->clone_skb = pg_clone_skb_d;
	pkt_dev->delay_us = pg_delay_d / 1000;
	pkt_dev->delay_ns = pg_delay_d % 1000;
	pkt_dev->count = pg_count_d;
	pkt_dev->sofar = 0;
L
Luiz Capitulino 已提交
3631
	pkt_dev->udp_src_min = 9;	/* sink port */
3632 3633 3634 3635
	pkt_dev->udp_src_max = 9;
	pkt_dev->udp_dst_min = 9;
	pkt_dev->udp_dst_max = 9;

F
Francesco Fondelli 已提交
3636 3637 3638 3639 3640 3641 3642
	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;

3643 3644 3645
	err = pktgen_setup_dev(pkt_dev, ifname);
	if (err)
		goto out1;
3646

3647 3648
	pkt_dev->entry = create_proc_entry(ifname, 0600, pg_proc_dir);
	if (!pkt_dev->entry) {
3649
		printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
3650
		       PG_PROC_DIR, ifname);
3651 3652
		err = -EINVAL;
		goto out2;
3653
	}
3654 3655
	pkt_dev->entry->proc_fops = &pktgen_if_fops;
	pkt_dev->entry->data = pkt_dev;
J
Jamal Hadi Salim 已提交
3656 3657 3658 3659
#ifdef CONFIG_XFRM
	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
	pkt_dev->ipsproto = IPPROTO_ESP;
#endif
3660 3661

	return add_dev_to_thread(t, pkt_dev);
3662 3663 3664
out2:
	dev_put(pkt_dev->odev);
out1:
J
Jamal Hadi Salim 已提交
3665 3666 3667
#ifdef CONFIG_XFRM
	free_SAs(pkt_dev);
#endif
3668 3669 3670 3671
	if (pkt_dev->flows)
		vfree(pkt_dev->flows);
	kfree(pkt_dev);
	return err;
L
Linus Torvalds 已提交
3672 3673
}

3674
static int __init pktgen_create_thread(int cpu)
L
Linus Torvalds 已提交
3675
{
3676
	struct pktgen_thread *t;
3677
	struct proc_dir_entry *pe;
3678
	struct task_struct *p;
L
Luiz Capitulino 已提交
3679 3680 3681

	t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
	if (!t) {
3682 3683
		printk(KERN_ERR "pktgen: ERROR: out of memory, can't "
		       "create new thread.\n");
L
Luiz Capitulino 已提交
3684 3685 3686 3687
		return -ENOMEM;
	}

	spin_lock_init(&t->if_lock);
L
Linus Torvalds 已提交
3688
	t->cpu = cpu;
L
Luiz Capitulino 已提交
3689

3690 3691 3692 3693 3694 3695
	INIT_LIST_HEAD(&t->if_list);

	list_add_tail(&t->th_list, &pktgen_threads);

	p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
	if (IS_ERR(p)) {
3696 3697
		printk(KERN_ERR "pktgen: kernel_thread() failed "
		       "for cpu %d\n", t->cpu);
3698 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;

	pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir);
L
Luiz Capitulino 已提交
3706
	if (!pe) {
3707
		printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
3708 3709 3710
		       PG_PROC_DIR, t->tsk->comm);
		kthread_stop(p);
		list_del(&t->th_list);
L
Luiz Capitulino 已提交
3711 3712 3713
		kfree(t);
		return -EINVAL;
	}
3714 3715 3716

	pe->proc_fops = &pktgen_thread_fops;
	pe->data = t;
L
Linus Torvalds 已提交
3717

3718
	wake_up_process(p);
L
Linus Torvalds 已提交
3719 3720 3721 3722

	return 0;
}

3723 3724
/*
 * Removes a device from the thread if_list.
L
Linus Torvalds 已提交
3725
 */
L
Luiz Capitulino 已提交
3726 3727
static void _rem_dev_from_if_list(struct pktgen_thread *t,
				  struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3728
{
3729 3730
	struct list_head *q, *n;
	struct pktgen_dev *p;
L
Linus Torvalds 已提交
3731

3732 3733 3734 3735
	list_for_each_safe(q, n, &t->if_list) {
		p = list_entry(q, struct pktgen_dev, list);
		if (p == pkt_dev)
			list_del(&p->list);
L
Linus Torvalds 已提交
3736 3737 3738
	}
}

L
Luiz Capitulino 已提交
3739 3740
static int pktgen_remove_device(struct pktgen_thread *t,
				struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3741 3742
{

S
Stephen Hemminger 已提交
3743
	pr_debug("pktgen: remove_device pkt_dev=%p\n", pkt_dev);
L
Linus Torvalds 已提交
3744

L
Luiz Capitulino 已提交
3745
	if (pkt_dev->running) {
3746 3747
		printk(KERN_WARNING "pktgen: WARNING: trying to remove a "
		       "running interface, stopping it now.\n");
L
Luiz Capitulino 已提交
3748 3749 3750 3751
		pktgen_stop_device(pkt_dev);
	}

	/* Dis-associate from the interface */
L
Linus Torvalds 已提交
3752 3753 3754

	if (pkt_dev->odev) {
		dev_put(pkt_dev->odev);
L
Luiz Capitulino 已提交
3755 3756 3757
		pkt_dev->odev = NULL;
	}

L
Linus Torvalds 已提交
3758 3759 3760 3761
	/* And update the thread if_list */

	_rem_dev_from_if_list(t, pkt_dev);

3762 3763
	if (pkt_dev->entry)
		remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
L
Linus Torvalds 已提交
3764

J
Jamal Hadi Salim 已提交
3765 3766 3767
#ifdef CONFIG_XFRM
	free_SAs(pkt_dev);
#endif
L
Linus Torvalds 已提交
3768 3769 3770
	if (pkt_dev->flows)
		vfree(pkt_dev->flows);
	kfree(pkt_dev);
L
Luiz Capitulino 已提交
3771
	return 0;
L
Linus Torvalds 已提交
3772 3773
}

L
Luiz Capitulino 已提交
3774
static int __init pg_init(void)
L
Linus Torvalds 已提交
3775 3776
{
	int cpu;
3777
	struct proc_dir_entry *pe;
L
Linus Torvalds 已提交
3778

3779
	printk(KERN_INFO "%s", version);
L
Linus Torvalds 已提交
3780

3781 3782 3783 3784
	pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net);
	if (!pg_proc_dir)
		return -ENODEV;
	pg_proc_dir->owner = THIS_MODULE;
L
Linus Torvalds 已提交
3785

3786
	pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir);
L
Luiz Capitulino 已提交
3787
	if (pe == NULL) {
3788 3789
		printk(KERN_ERR "pktgen: ERROR: cannot create %s "
		       "procfs entry.\n", PGCTRL);
3790
		proc_net_remove(PG_PROC_DIR);
L
Luiz Capitulino 已提交
3791 3792
		return -EINVAL;
	}
L
Linus Torvalds 已提交
3793

L
Luiz Capitulino 已提交
3794 3795
	pe->proc_fops = &pktgen_fops;
	pe->data = NULL;
L
Linus Torvalds 已提交
3796 3797 3798

	/* Register us to receive netdevice events */
	register_netdevice_notifier(&pktgen_notifier_block);
L
Luiz Capitulino 已提交
3799

J
John Hawkes 已提交
3800
	for_each_online_cpu(cpu) {
3801
		int err;
L
Linus Torvalds 已提交
3802

3803
		err = pktgen_create_thread(cpu);
3804
		if (err)
3805 3806
			printk(KERN_WARNING "pktgen: WARNING: Cannot create "
			       "thread for cpu %d (%d)\n", cpu, err);
L
Luiz Capitulino 已提交
3807
	}
3808 3809

	if (list_empty(&pktgen_threads)) {
3810 3811
		printk(KERN_ERR "pktgen: ERROR: Initialization failed for "
		       "all threads\n");
3812 3813 3814 3815 3816 3817
		unregister_netdevice_notifier(&pktgen_notifier_block);
		remove_proc_entry(PGCTRL, pg_proc_dir);
		proc_net_remove(PG_PROC_DIR);
		return -ENODEV;
	}

L
Luiz Capitulino 已提交
3818
	return 0;
L
Linus Torvalds 已提交
3819 3820 3821 3822
}

static void __exit pg_cleanup(void)
{
3823 3824
	struct pktgen_thread *t;
	struct list_head *q, *n;
L
Linus Torvalds 已提交
3825 3826 3827
	wait_queue_head_t queue;
	init_waitqueue_head(&queue);

L
Luiz Capitulino 已提交
3828
	/* Stop all interfaces & threads */
L
Linus Torvalds 已提交
3829

3830 3831
	list_for_each_safe(q, n, &pktgen_threads) {
		t = list_entry(q, struct pktgen_thread, th_list);
3832 3833
		kthread_stop(t->tsk);
		kfree(t);
L
Luiz Capitulino 已提交
3834
	}
L
Linus Torvalds 已提交
3835

L
Luiz Capitulino 已提交
3836
	/* Un-register us from receiving netdevice events */
L
Linus Torvalds 已提交
3837 3838
	unregister_netdevice_notifier(&pktgen_notifier_block);

L
Luiz Capitulino 已提交
3839
	/* Clean up proc file system */
3840 3841
	remove_proc_entry(PGCTRL, pg_proc_dir);
	proc_net_remove(PG_PROC_DIR);
L
Linus Torvalds 已提交
3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853
}

module_init(pg_init);
module_exit(pg_cleanup);

MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
MODULE_DESCRIPTION("Packet Generator tool");
MODULE_LICENSE("GPL");
module_param(pg_count_d, int, 0);
module_param(pg_delay_d, int, 0);
module_param(pg_clone_skb_d, int, 0);
module_param(debug, int, 0);