pktgen.c 90.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 * Authors:
 * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
 *                             Uppsala University and
 *                             Swedish University of Agricultural Sciences
 *
 * Alexey Kuznetsov  <kuznet@ms2.inr.ac.ru>
 * Ben Greear <greearb@candelatech.com>
9
 * Jens Låås <jens.laas@data.slu.se>
L
Linus Torvalds 已提交
10 11 12 13 14 15 16 17
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 *
 * A tool for loading the network with preconfigurated packets.
18
 * The tool is implemented as a linux module.  Parameters are output
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>
155
#include <net/net_namespace.h>
L
Linus Torvalds 已提交
156 157 158
#include <net/checksum.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
J
Jamal Hadi Salim 已提交
159 160 161
#ifdef CONFIG_XFRM
#include <net/xfrm.h>
#endif
L
Linus Torvalds 已提交
162 163
#include <asm/byteorder.h>
#include <linux/rcupdate.h>
J
Jiri Slaby 已提交
164
#include <linux/bitops.h>
L
Linus Torvalds 已提交
165 166 167
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
L
Luiz Capitulino 已提交
168
#include <asm/div64.h>		/* do_div */
L
Linus Torvalds 已提交
169 170
#include <asm/timex.h>

171
#define VERSION  "pktgen v2.69: Packet Generator for packet performance testing.\n"
L
Linus Torvalds 已提交
172 173

#define IP_NAME_SZ 32
174
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
175
#define MPLS_STACK_BOTTOM htonl(0x00000100)
L
Linus Torvalds 已提交
176 177

/* Device flag bits */
L
Luiz Capitulino 已提交
178 179 180 181 182 183 184 185
#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 */
186
#define F_MPLS_RND    (1<<8)	/* Random MPLS labels */
F
Francesco Fondelli 已提交
187 188
#define F_VID_RND     (1<<9)	/* Random VLAN ID */
#define F_SVID_RND    (1<<10)	/* Random SVLAN ID */
189
#define F_FLOW_SEQ    (1<<11)	/* Sequential flows */
J
Jamal Hadi Salim 已提交
190
#define F_IPSEC_ON    (1<<12)	/* ipsec on for flows */
R
Robert Olsson 已提交
191
#define F_QUEUE_MAP_RND (1<<13)	/* queue map Random */
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
	__u16 cur_udp_dst;
	__u16 cur_udp_src;
R
Robert Olsson 已提交
334
	__u16 cur_queue_map;
L
Luiz Capitulino 已提交
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	__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 已提交
357
	struct flow_state *flows;
L
Luiz Capitulino 已提交
358 359 360
	unsigned cflows;	/* Concurrent flows (config) */
	unsigned lflow;		/* Flow length  (config) */
	unsigned nflows;	/* accumulated flows (stats) */
361
	unsigned curfl;		/* current sequenced flow (state)*/
R
Robert Olsson 已提交
362 363 364 365

	u16 queue_map_min;
	u16 queue_map_max;

J
Jamal Hadi Salim 已提交
366 367 368 369
#ifdef CONFIG_XFRM
	__u8	ipsmode;		/* IPSEC mode (config) */
	__u8	ipsproto;		/* IPSEC type (config) */
#endif
370
	char result[512];
L
Linus Torvalds 已提交
371 372 373
};

struct pktgen_hdr {
A
Al Viro 已提交
374 375 376 377
	__be32 pgh_magic;
	__be32 seq_num;
	__be32 tv_sec;
	__be32 tv_usec;
L
Linus Torvalds 已提交
378 379 380
};

struct pktgen_thread {
L
Luiz Capitulino 已提交
381
	spinlock_t if_lock;
382
	struct list_head if_list;	/* All device here */
383
	struct list_head th_list;
384
	struct task_struct *tsk;
L
Luiz Capitulino 已提交
385 386 387 388 389
	char result[512];

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

	u32 control;
L
Linus Torvalds 已提交
390 391
	int cpu;

L
Luiz Capitulino 已提交
392
	wait_queue_head_t queue;
L
Linus Torvalds 已提交
393 394 395 396 397 398
};

#define REMOVE 1
#define FIND   0

/** Convert to micro-seconds */
L
Luiz Capitulino 已提交
399
static inline __u64 tv_to_us(const struct timeval *tv)
L
Linus Torvalds 已提交
400
{
L
Luiz Capitulino 已提交
401 402 403
	__u64 us = tv->tv_usec;
	us += (__u64) tv->tv_sec * (__u64) 1000000;
	return us;
L
Linus Torvalds 已提交
404 405
}

I
Ilpo Järvinen 已提交
406
static __u64 getCurUs(void)
L
Linus Torvalds 已提交
407
{
L
Luiz Capitulino 已提交
408 409 410
	struct timeval tv;
	do_gettimeofday(&tv);
	return tv_to_us(&tv);
L
Linus Torvalds 已提交
411 412 413 414 415 416
}

/* old include end */

static char version[] __initdata = VERSION;

L
Luiz Capitulino 已提交
417 418 419 420
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 已提交
421 422 423 424
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 已提交
425
static void pktgen_stop(struct pktgen_thread *t);
L
Linus Torvalds 已提交
426
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
427

L
Luiz Capitulino 已提交
428 429
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 已提交
430 431

/* Module parameters, defaults. */
L
Luiz Capitulino 已提交
432
static int pg_count_d = 1000;	/* 1000 pkts by default */
433 434 435
static int pg_delay_d;
static int pg_clone_skb_d;
static int debug;
L
Linus Torvalds 已提交
436

437
static DEFINE_MUTEX(pktgen_thread_lock);
438
static LIST_HEAD(pktgen_threads);
L
Linus Torvalds 已提交
439 440 441 442 443 444

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

/*
445
 * /proc handling functions
L
Linus Torvalds 已提交
446 447 448
 *
 */

449
static int pgctrl_show(struct seq_file *seq, void *v)
L
Luiz Capitulino 已提交
450
{
451 452
	seq_puts(seq, VERSION);
	return 0;
L
Linus Torvalds 已提交
453 454
}

L
Luiz Capitulino 已提交
455 456
static ssize_t pgctrl_write(struct file *file, const char __user * buf,
			    size_t count, loff_t * ppos)
L
Linus Torvalds 已提交
457 458
{
	int err = 0;
459
	char data[128];
L
Linus Torvalds 已提交
460

L
Luiz Capitulino 已提交
461 462
	if (!capable(CAP_NET_ADMIN)) {
		err = -EPERM;
L
Linus Torvalds 已提交
463
		goto out;
L
Luiz Capitulino 已提交
464
	}
L
Linus Torvalds 已提交
465

466 467
	if (count > sizeof(data))
		count = sizeof(data);
L
Linus Torvalds 已提交
468 469

	if (copy_from_user(data, buf, count)) {
470
		err = -EFAULT;
471
		goto out;
L
Luiz Capitulino 已提交
472 473
	}
	data[count - 1] = 0;	/* Make string */
L
Linus Torvalds 已提交
474

L
Luiz Capitulino 已提交
475
	if (!strcmp(data, "stop"))
L
Linus Torvalds 已提交
476 477
		pktgen_stop_all_threads_ifs();

L
Luiz Capitulino 已提交
478
	else if (!strcmp(data, "start"))
L
Linus Torvalds 已提交
479 480
		pktgen_run_all_threads();

L
Luiz Capitulino 已提交
481
	else
482
		printk(KERN_WARNING "pktgen: Unknown command: %s\n", data);
L
Linus Torvalds 已提交
483 484 485

	err = count;

L
Luiz Capitulino 已提交
486 487
out:
	return err;
L
Linus Torvalds 已提交
488 489
}

490 491 492 493 494
static int pgctrl_open(struct inode *inode, struct file *file)
{
	return single_open(file, pgctrl_show, PDE(inode)->data);
}

495
static const struct file_operations pktgen_fops = {
L
Luiz Capitulino 已提交
496 497 498 499 500 501
	.owner   = THIS_MODULE,
	.open    = pgctrl_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pgctrl_write,
	.release = single_release,
502 503 504
};

static int pktgen_if_show(struct seq_file *seq, void *v)
L
Linus Torvalds 已提交
505
{
L
Luiz Capitulino 已提交
506 507 508 509
	struct pktgen_dev *pkt_dev = seq->private;
	__u64 sa;
	__u64 stopped;
	__u64 now = getCurUs();
510
	DECLARE_MAC_BUF(mac);
L
Luiz Capitulino 已提交
511 512 513 514 515 516 517 518 519 520

	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,
521
		   pkt_dev->clone_skb, pkt_dev->odev->name);
L
Luiz Capitulino 已提交
522 523 524 525

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

R
Robert Olsson 已提交
526 527 528 529 530
	seq_printf(seq,
		   "     queue_map_min: %u  queue_map_max: %u\n",
		   pkt_dev->queue_map_min,
		   pkt_dev->queue_map_max);

L
Luiz Capitulino 已提交
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
	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 已提交
552

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

555 556 557
	seq_printf(seq, "%s ",
		   print_mac(mac, is_zero_ether_addr(pkt_dev->src_mac) ?
			     pkt_dev->odev->dev_addr : pkt_dev->src_mac));
L
Luiz Capitulino 已提交
558 559

	seq_printf(seq, "dst_mac: ");
560
	seq_printf(seq, "%s\n", print_mac(mac, pkt_dev->dst_mac));
L
Luiz Capitulino 已提交
561 562 563 564 565 566 567

	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,
568
		   "     src_mac_count: %d  dst_mac_count: %d\n",
L
Luiz Capitulino 已提交
569
		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
L
Linus Torvalds 已提交
570

571 572 573
	if (pkt_dev->nr_labels) {
		unsigned i;
		seq_printf(seq, "     mpls: ");
574
		for (i = 0; i < pkt_dev->nr_labels; i++)
575 576 577 578
			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
	}

F
Francesco Fondelli 已提交
579 580 581 582 583 584 585 586 587 588
	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 已提交
589 590 591 592 593 594 595 596
	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);
	}

597 598
	seq_printf(seq, "     Flags: ");

L
Luiz Capitulino 已提交
599 600
	if (pkt_dev->flags & F_IPV6)
		seq_printf(seq, "IPV6  ");
L
Linus Torvalds 已提交
601

L
Luiz Capitulino 已提交
602 603
	if (pkt_dev->flags & F_IPSRC_RND)
		seq_printf(seq, "IPSRC_RND  ");
L
Linus Torvalds 已提交
604

L
Luiz Capitulino 已提交
605 606
	if (pkt_dev->flags & F_IPDST_RND)
		seq_printf(seq, "IPDST_RND  ");
L
Linus Torvalds 已提交
607

L
Luiz Capitulino 已提交
608 609
	if (pkt_dev->flags & F_TXSIZE_RND)
		seq_printf(seq, "TXSIZE_RND  ");
L
Linus Torvalds 已提交
610

L
Luiz Capitulino 已提交
611 612
	if (pkt_dev->flags & F_UDPSRC_RND)
		seq_printf(seq, "UDPSRC_RND  ");
L
Linus Torvalds 已提交
613

L
Luiz Capitulino 已提交
614 615
	if (pkt_dev->flags & F_UDPDST_RND)
		seq_printf(seq, "UDPDST_RND  ");
L
Linus Torvalds 已提交
616

617 618 619
	if (pkt_dev->flags & F_MPLS_RND)
		seq_printf(seq,  "MPLS_RND  ");

R
Robert Olsson 已提交
620 621 622
	if (pkt_dev->flags & F_QUEUE_MAP_RND)
		seq_printf(seq,  "QUEUE_MAP_RND  ");

623 624 625 626 627 628 629
	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 已提交
630 631 632 633 634
#ifdef CONFIG_XFRM
	if (pkt_dev->flags & F_IPSEC_ON)
		seq_printf(seq,  "IPSEC  ");
#endif

L
Luiz Capitulino 已提交
635 636
	if (pkt_dev->flags & F_MACSRC_RND)
		seq_printf(seq, "MACSRC_RND  ");
L
Linus Torvalds 已提交
637

L
Luiz Capitulino 已提交
638 639
	if (pkt_dev->flags & F_MACDST_RND)
		seq_printf(seq, "MACDST_RND  ");
L
Linus Torvalds 已提交
640

F
Francesco Fondelli 已提交
641 642 643 644 645 646
	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 已提交
647 648 649 650 651 652
	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 已提交
653

L
Luiz Capitulino 已提交
654 655 656 657 658 659
	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 已提交
660

L
Luiz Capitulino 已提交
661 662
	seq_printf(seq,
		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
663 664
		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
		   pkt_dev->cur_src_mac_offset);
L
Linus Torvalds 已提交
665

L
Luiz Capitulino 已提交
666
	if (pkt_dev->flags & F_IPV6) {
L
Linus Torvalds 已提交
667
		char b1[128], b2[128];
L
Luiz Capitulino 已提交
668 669 670 671 672
		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",
673
			   pkt_dev->cur_saddr, pkt_dev->cur_daddr);
L
Linus Torvalds 已提交
674

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

R
Robert Olsson 已提交
678 679
	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);

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

	if (pkt_dev->result[0])
L
Luiz Capitulino 已提交
683
		seq_printf(seq, "Result: %s\n", pkt_dev->result);
L
Linus Torvalds 已提交
684
	else
L
Luiz Capitulino 已提交
685
		seq_printf(seq, "Result: Idle\n");
L
Linus Torvalds 已提交
686

687
	return 0;
L
Linus Torvalds 已提交
688 689
}

690

F
Francesco Fondelli 已提交
691
static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num)
692 693 694 695
{
	int i = 0;
	*num = 0;

696
	for (; i < maxlen; i++) {
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
		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 已提交
713 714
static int count_trail_chars(const char __user * user_buffer,
			     unsigned int maxlen)
L
Linus Torvalds 已提交
715 716 717 718
{
	int i;

	for (i = 0; i < maxlen; i++) {
L
Luiz Capitulino 已提交
719 720 721 722
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
L
Linus Torvalds 已提交
723 724 725 726 727 728 729 730 731
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
		case '=':
			break;
		default:
			goto done;
732
		}
L
Linus Torvalds 已提交
733 734 735 736 737
	}
done:
	return i;
}

L
Luiz Capitulino 已提交
738 739
static unsigned long num_arg(const char __user * user_buffer,
			     unsigned long maxlen, unsigned long *num)
L
Linus Torvalds 已提交
740 741 742
{
	int i = 0;
	*num = 0;
L
Luiz Capitulino 已提交
743 744 745 746 747 748

	for (; i < maxlen; i++) {
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		if ((c >= '0') && (c <= '9')) {
L
Linus Torvalds 已提交
749
			*num *= 10;
L
Luiz Capitulino 已提交
750
			*num += c - '0';
L
Linus Torvalds 已提交
751 752 753 754 755 756
		} else
			break;
	}
	return i;
}

L
Luiz Capitulino 已提交
757
static int strn_len(const char __user * user_buffer, unsigned int maxlen)
L
Linus Torvalds 已提交
758 759 760
{
	int i = 0;

L
Luiz Capitulino 已提交
761 762 763 764 765
	for (; i < maxlen; i++) {
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
L
Linus Torvalds 已提交
766 767 768 769 770 771 772 773 774
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
			goto done_str;
			break;
		default:
			break;
775
		}
L
Linus Torvalds 已提交
776 777 778 779 780
	}
done_str:
	return i;
}

781 782 783 784 785 786 787 788 789 790
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 已提交
791
		len = hex32_arg(&buffer[i], 8, &tmp);
792 793 794 795 796 797 798 799 800 801 802 803
		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;
804
	} while (c == ',');
805 806 807 808 809

	pkt_dev->nr_labels = n;
	return i;
}

L
Luiz Capitulino 已提交
810 811 812
static ssize_t pktgen_if_write(struct file *file,
			       const char __user * user_buffer, size_t count,
			       loff_t * offset)
L
Linus Torvalds 已提交
813
{
L
Luiz Capitulino 已提交
814 815
	struct seq_file *seq = (struct seq_file *)file->private_data;
	struct pktgen_dev *pkt_dev = seq->private;
L
Linus Torvalds 已提交
816 817 818
	int i = 0, max, len;
	char name[16], valstr[32];
	unsigned long value = 0;
L
Luiz Capitulino 已提交
819 820
	char *pg_result = NULL;
	int tmp = 0;
L
Linus Torvalds 已提交
821
	char buf[128];
L
Luiz Capitulino 已提交
822 823 824

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

L
Linus Torvalds 已提交
825
	if (count < 1) {
826
		printk(KERN_WARNING "pktgen: wrong command format\n");
L
Linus Torvalds 已提交
827 828
		return -EINVAL;
	}
L
Luiz Capitulino 已提交
829

L
Linus Torvalds 已提交
830 831
	max = count - i;
	tmp = count_trail_chars(&user_buffer[i], max);
L
Luiz Capitulino 已提交
832
	if (tmp < 0) {
833
		printk(KERN_WARNING "pktgen: illegal format\n");
L
Luiz Capitulino 已提交
834
		return tmp;
L
Linus Torvalds 已提交
835
	}
L
Luiz Capitulino 已提交
836 837
	i += tmp;

L
Linus Torvalds 已提交
838 839 840
	/* Read variable name */

	len = strn_len(&user_buffer[i], sizeof(name) - 1);
L
Luiz Capitulino 已提交
841 842 843
	if (len < 0) {
		return len;
	}
L
Linus Torvalds 已提交
844
	memset(name, 0, sizeof(name));
L
Luiz Capitulino 已提交
845
	if (copy_from_user(name, &user_buffer[i], len))
L
Linus Torvalds 已提交
846 847
		return -EFAULT;
	i += len;
L
Luiz Capitulino 已提交
848 849

	max = count - i;
L
Linus Torvalds 已提交
850
	len = count_trail_chars(&user_buffer[i], max);
L
Luiz Capitulino 已提交
851 852 853
	if (len < 0)
		return len;

L
Linus Torvalds 已提交
854 855 856
	i += len;

	if (debug) {
L
Luiz Capitulino 已提交
857 858
		char tb[count + 1];
		if (copy_from_user(tb, user_buffer, count))
L
Linus Torvalds 已提交
859
			return -EFAULT;
L
Luiz Capitulino 已提交
860
		tb[count] = 0;
861
		printk(KERN_DEBUG "pktgen: %s,%lu  buffer -:%s:-\n", name,
L
Luiz Capitulino 已提交
862 863
		       (unsigned long)count, tb);
	}
L
Linus Torvalds 已提交
864 865 866

	if (!strcmp(name, "min_pkt_size")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
867 868 869
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
870
		i += len;
L
Luiz Capitulino 已提交
871 872 873 874 875 876 877 878
		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 已提交
879 880 881
		return count;
	}

L
Luiz Capitulino 已提交
882
	if (!strcmp(name, "max_pkt_size")) {
L
Linus Torvalds 已提交
883
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
884 885 886
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
887
		i += len;
L
Luiz Capitulino 已提交
888 889 890 891 892 893 894 895
		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 已提交
896 897 898
		return count;
	}

L
Luiz Capitulino 已提交
899
	/* Shortcut for min = max */
L
Linus Torvalds 已提交
900 901 902

	if (!strcmp(name, "pkt_size")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
903 904 905
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
906
		i += len;
L
Luiz Capitulino 已提交
907 908 909 910 911 912 913
		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 已提交
914 915 916 917
		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
		return count;
	}

L
Luiz Capitulino 已提交
918
	if (!strcmp(name, "debug")) {
L
Linus Torvalds 已提交
919
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
920 921 922
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
923
		i += len;
L
Luiz Capitulino 已提交
924
		debug = value;
L
Linus Torvalds 已提交
925 926 927 928
		sprintf(pg_result, "OK: debug=%u", debug);
		return count;
	}

L
Luiz Capitulino 已提交
929
	if (!strcmp(name, "frags")) {
L
Linus Torvalds 已提交
930
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
931 932 933
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
934 935 936 937 938 939 940
		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 已提交
941 942 943
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
944 945 946 947 948 949 950 951
		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 已提交
952 953
		sprintf(pg_result, "OK: delay=%u",
			1000 * pkt_dev->delay_us + pkt_dev->delay_ns);
L
Linus Torvalds 已提交
954 955
		return count;
	}
L
Luiz Capitulino 已提交
956
	if (!strcmp(name, "udp_src_min")) {
L
Linus Torvalds 已提交
957
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
958 959 960
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
961
		i += len;
L
Luiz Capitulino 已提交
962 963 964 965
		if (value != pkt_dev->udp_src_min) {
			pkt_dev->udp_src_min = value;
			pkt_dev->cur_udp_src = value;
		}
L
Linus Torvalds 已提交
966 967 968
		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
		return count;
	}
L
Luiz Capitulino 已提交
969
	if (!strcmp(name, "udp_dst_min")) {
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
		if (value != pkt_dev->udp_dst_min) {
			pkt_dev->udp_dst_min = value;
			pkt_dev->cur_udp_dst = value;
		}
L
Linus Torvalds 已提交
979 980 981
		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
		return count;
	}
L
Luiz Capitulino 已提交
982
	if (!strcmp(name, "udp_src_max")) {
L
Linus Torvalds 已提交
983
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
984 985 986
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
987
		i += len;
L
Luiz Capitulino 已提交
988 989 990 991
		if (value != pkt_dev->udp_src_max) {
			pkt_dev->udp_src_max = value;
			pkt_dev->cur_udp_src = value;
		}
L
Linus Torvalds 已提交
992 993 994
		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
		return count;
	}
L
Luiz Capitulino 已提交
995
	if (!strcmp(name, "udp_dst_max")) {
L
Linus Torvalds 已提交
996
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
997 998 999
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1000
		i += len;
L
Luiz Capitulino 已提交
1001 1002 1003 1004
		if (value != pkt_dev->udp_dst_max) {
			pkt_dev->udp_dst_max = value;
			pkt_dev->cur_udp_dst = value;
		}
L
Linus Torvalds 已提交
1005 1006 1007 1008 1009
		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 已提交
1010 1011 1012
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1013
		i += len;
L
Luiz Capitulino 已提交
1014 1015
		pkt_dev->clone_skb = value;

L
Linus Torvalds 已提交
1016 1017 1018 1019 1020
		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 已提交
1021 1022 1023
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1024 1025 1026
		i += len;
		pkt_dev->count = value;
		sprintf(pg_result, "OK: count=%llu",
L
Luiz Capitulino 已提交
1027
			(unsigned long long)pkt_dev->count);
L
Linus Torvalds 已提交
1028 1029 1030 1031
		return count;
	}
	if (!strcmp(name, "src_mac_count")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1032 1033 1034
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1035 1036
		i += len;
		if (pkt_dev->src_mac_count != value) {
L
Luiz Capitulino 已提交
1037 1038 1039 1040 1041
			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 已提交
1042 1043 1044 1045
		return count;
	}
	if (!strcmp(name, "dst_mac_count")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1046 1047 1048
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1049 1050
		i += len;
		if (pkt_dev->dst_mac_count != value) {
L
Luiz Capitulino 已提交
1051 1052 1053 1054 1055
			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 已提交
1056 1057 1058
		return count;
	}
	if (!strcmp(name, "flag")) {
L
Luiz Capitulino 已提交
1059 1060
		char f[32];
		memset(f, 0, 32);
L
Linus Torvalds 已提交
1061
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
L
Luiz Capitulino 已提交
1062 1063 1064
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1065 1066 1067
		if (copy_from_user(f, &user_buffer[i], len))
			return -EFAULT;
		i += len;
L
Luiz Capitulino 已提交
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
		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;

1110 1111 1112 1113 1114 1115
		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 已提交
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
		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;

1128 1129 1130
		else if (strcmp(f, "FLOW_SEQ") == 0)
			pkt_dev->flags |= F_FLOW_SEQ;

R
Robert Olsson 已提交
1131 1132 1133 1134 1135
		else if (strcmp(f, "QUEUE_MAP_RND") == 0)
			pkt_dev->flags |= F_QUEUE_MAP_RND;

		else if (strcmp(f, "!QUEUE_MAP_RND") == 0)
			pkt_dev->flags &= ~F_QUEUE_MAP_RND;
J
Jamal Hadi Salim 已提交
1136 1137 1138 1139 1140
#ifdef CONFIG_XFRM
		else if (strcmp(f, "IPSEC") == 0)
			pkt_dev->flags |= F_IPSEC_ON;
#endif

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

L
Luiz Capitulino 已提交
1144 1145 1146 1147
		else {
			sprintf(pg_result,
				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
				f,
F
Francesco Fondelli 已提交
1148
				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
J
Jamal Hadi Salim 已提交
1149
				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n");
L
Luiz Capitulino 已提交
1150 1151
			return count;
		}
L
Linus Torvalds 已提交
1152 1153 1154 1155 1156
		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 已提交
1157 1158 1159
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1160

L
Luiz Capitulino 已提交
1161
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1162
			return -EFAULT;
L
Luiz Capitulino 已提交
1163 1164 1165 1166 1167 1168 1169 1170
		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)
1171
			printk(KERN_DEBUG "pktgen: dst_min set to: %s\n",
L
Luiz Capitulino 已提交
1172 1173
			       pkt_dev->dst_min);
		i += len;
L
Linus Torvalds 已提交
1174 1175 1176 1177 1178
		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 已提交
1179 1180 1181
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1182

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

L
Luiz Capitulino 已提交
1186 1187 1188 1189 1190 1191 1192 1193
		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)
1194
			printk(KERN_DEBUG "pktgen: dst_max set to: %s\n",
L
Luiz Capitulino 已提交
1195
			       pkt_dev->dst_max);
L
Linus Torvalds 已提交
1196 1197 1198 1199 1200 1201
		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 已提交
1202 1203
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1204 1205 1206

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1207
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1208
			return -EFAULT;
L
Luiz Capitulino 已提交
1209
		buf[len] = 0;
L
Linus Torvalds 已提交
1210 1211

		scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
L
Luiz Capitulino 已提交
1212
		fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
L
Linus Torvalds 已提交
1213 1214 1215

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

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

L
Luiz Capitulino 已提交
1219
		i += len;
L
Linus Torvalds 已提交
1220 1221 1222 1223 1224
		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 已提交
1225 1226
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1227 1228 1229

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1230
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1231
			return -EFAULT;
L
Luiz Capitulino 已提交
1232
		buf[len] = 0;
L
Linus Torvalds 已提交
1233 1234

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

L
Luiz Capitulino 已提交
1237 1238 1239
		ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
			       &pkt_dev->min_in6_daddr);
		if (debug)
1240
			printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
L
Linus Torvalds 已提交
1241

L
Luiz Capitulino 已提交
1242
		i += len;
L
Linus Torvalds 已提交
1243 1244 1245 1246 1247
		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 已提交
1248 1249
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1250 1251 1252

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1253
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1254
			return -EFAULT;
L
Luiz Capitulino 已提交
1255
		buf[len] = 0;
L
Linus Torvalds 已提交
1256 1257

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

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

L
Luiz Capitulino 已提交
1263
		i += len;
L
Linus Torvalds 已提交
1264 1265 1266 1267 1268
		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 已提交
1269 1270
		if (len < 0)
			return len;
L
Linus Torvalds 已提交
1271 1272 1273

		pkt_dev->flags |= F_IPV6;

L
Luiz Capitulino 已提交
1274
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1275
			return -EFAULT;
L
Luiz Capitulino 已提交
1276
		buf[len] = 0;
L
Linus Torvalds 已提交
1277 1278

		scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
L
Luiz Capitulino 已提交
1279
		fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
L
Linus Torvalds 已提交
1280 1281 1282

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

L
Luiz Capitulino 已提交
1283
		if (debug)
1284
			printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
L
Luiz Capitulino 已提交
1285 1286

		i += len;
L
Linus Torvalds 已提交
1287 1288 1289 1290 1291
		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 已提交
1292 1293 1294 1295
		if (len < 0) {
			return len;
		}
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1296
			return -EFAULT;
L
Luiz Capitulino 已提交
1297 1298 1299 1300 1301 1302 1303 1304
		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)
1305
			printk(KERN_DEBUG "pktgen: src_min set to: %s\n",
L
Luiz Capitulino 已提交
1306
			       pkt_dev->src_min);
L
Linus Torvalds 已提交
1307 1308 1309 1310 1311 1312
		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 已提交
1313 1314 1315 1316
		if (len < 0) {
			return len;
		}
		if (copy_from_user(buf, &user_buffer[i], len))
L
Linus Torvalds 已提交
1317
			return -EFAULT;
L
Luiz Capitulino 已提交
1318 1319 1320 1321 1322 1323 1324 1325
		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)
1326
			printk(KERN_DEBUG "pktgen: src_max set to: %s\n",
L
Luiz Capitulino 已提交
1327
			       pkt_dev->src_max);
L
Linus Torvalds 已提交
1328 1329 1330 1331 1332 1333
		i += len;
		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
		return count;
	}
	if (!strcmp(name, "dst_mac")) {
		char *v = valstr;
1334
		unsigned char old_dmac[ETH_ALEN];
L
Linus Torvalds 已提交
1335
		unsigned char *m = pkt_dev->dst_mac;
1336
		memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
L
Luiz Capitulino 已提交
1337

L
Linus Torvalds 已提交
1338
		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
L
Luiz Capitulino 已提交
1339 1340 1341
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1342
		memset(valstr, 0, sizeof(valstr));
L
Luiz Capitulino 已提交
1343
		if (copy_from_user(valstr, &user_buffer[i], len))
L
Linus Torvalds 已提交
1344 1345 1346
			return -EFAULT;
		i += len;

L
Luiz Capitulino 已提交
1347
		for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
L
Linus Torvalds 已提交
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
			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 */
1367 1368
		if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
			memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
L
Luiz Capitulino 已提交
1369

L
Linus Torvalds 已提交
1370 1371 1372 1373 1374
		sprintf(pg_result, "OK: dstmac");
		return count;
	}
	if (!strcmp(name, "src_mac")) {
		char *v = valstr;
A
Adit Ranadive 已提交
1375
		unsigned char old_smac[ETH_ALEN];
L
Linus Torvalds 已提交
1376 1377
		unsigned char *m = pkt_dev->src_mac;

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

L
Linus Torvalds 已提交
1380
		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
L
Luiz Capitulino 已提交
1381 1382 1383
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1384
		memset(valstr, 0, sizeof(valstr));
L
Luiz Capitulino 已提交
1385
		if (copy_from_user(valstr, &user_buffer[i], len))
L
Linus Torvalds 已提交
1386 1387 1388
			return -EFAULT;
		i += len;

L
Luiz Capitulino 已提交
1389
		for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
L
Linus Torvalds 已提交
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
			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 已提交
1406
		}
L
Linus Torvalds 已提交
1407

A
Adit Ranadive 已提交
1408 1409 1410 1411
		/* 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 已提交
1412
		sprintf(pg_result, "OK: srcmac");
L
Linus Torvalds 已提交
1413 1414 1415
		return count;
	}

L
Luiz Capitulino 已提交
1416 1417 1418 1419 1420
	if (!strcmp(name, "clear_counters")) {
		pktgen_clear_counters(pkt_dev);
		sprintf(pg_result, "OK: Clearing counters.\n");
		return count;
	}
L
Linus Torvalds 已提交
1421 1422 1423

	if (!strcmp(name, "flows")) {
		len = num_arg(&user_buffer[i], 10, &value);
L
Luiz Capitulino 已提交
1424 1425 1426
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
		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 已提交
1438 1439 1440
		if (len < 0) {
			return len;
		}
L
Linus Torvalds 已提交
1441 1442 1443 1444 1445
		i += len;
		pkt_dev->lflow = value;
		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
		return count;
	}
L
Luiz Capitulino 已提交
1446

R
Robert Olsson 已提交
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
	if (!strcmp(name, "queue_map_min")) {
		len = num_arg(&user_buffer[i], 5, &value);
		if (len < 0) {
			return len;
		}
		i += len;
		pkt_dev->queue_map_min = value;
		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
		return count;
	}

	if (!strcmp(name, "queue_map_max")) {
		len = num_arg(&user_buffer[i], 5, &value);
		if (len < 0) {
			return len;
		}
		i += len;
		pkt_dev->queue_map_max = value;
		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
		return count;
	}

1469
	if (!strcmp(name, "mpls")) {
S
Stephen Hemminger 已提交
1470 1471
		unsigned n, cnt;

1472
		len = get_labels(&user_buffer[i], pkt_dev);
S
Stephen Hemminger 已提交
1473 1474
		if (len < 0)
			return len;
1475
		i += len;
S
Stephen Hemminger 已提交
1476
		cnt = sprintf(pg_result, "OK: mpls=");
1477
		for (n = 0; n < pkt_dev->nr_labels; n++)
S
Stephen Hemminger 已提交
1478 1479 1480
			cnt += sprintf(pg_result + cnt,
				       "%08x%s", ntohl(pkt_dev->labels[n]),
				       n == pkt_dev->nr_labels-1 ? "" : ",");
F
Francesco Fondelli 已提交
1481 1482 1483 1484 1485 1486

		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)
1487
				printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n");
F
Francesco Fondelli 已提交
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
		}
		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)
1502
				printk(KERN_DEBUG "pktgen: VLAN turned on\n");
F
Francesco Fondelli 已提交
1503 1504

			if (debug && pkt_dev->nr_labels)
1505
				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
F
Francesco Fondelli 已提交
1506 1507 1508 1509 1510 1511 1512 1513

			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)
1514
				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
F
Francesco Fondelli 已提交
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
		}
		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)
1559
				printk(KERN_DEBUG "pktgen: SVLAN turned on\n");
F
Francesco Fondelli 已提交
1560 1561

			if (debug && pkt_dev->nr_labels)
1562
				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
F
Francesco Fondelli 已提交
1563 1564 1565 1566 1567 1568 1569 1570

			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)
1571
				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
F
Francesco Fondelli 已提交
1572 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
		}
		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");
		}
1603 1604 1605
		return count;
	}

F
Francesco Fondelli 已提交
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
	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 已提交
1638 1639 1640 1641
	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
	return -EINVAL;
}

1642
static int pktgen_if_open(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
1643
{
1644 1645
	return single_open(file, pktgen_if_show, PDE(inode)->data);
}
L
Linus Torvalds 已提交
1646

1647
static const struct file_operations pktgen_if_fops = {
L
Luiz Capitulino 已提交
1648 1649 1650 1651 1652 1653
	.owner   = THIS_MODULE,
	.open    = pktgen_if_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pktgen_if_write,
	.release = single_release,
1654
};
L
Linus Torvalds 已提交
1655

1656 1657
static int pktgen_thread_show(struct seq_file *seq, void *v)
{
L
Luiz Capitulino 已提交
1658
	struct pktgen_thread *t = seq->private;
1659
	struct pktgen_dev *pkt_dev;
1660 1661

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

L
Luiz Capitulino 已提交
1663
	seq_printf(seq, "Running: ");
L
Linus Torvalds 已提交
1664

L
Luiz Capitulino 已提交
1665
	if_lock(t);
1666
	list_for_each_entry(pkt_dev, &t->if_list, list)
L
Luiz Capitulino 已提交
1667
		if (pkt_dev->running)
1668
			seq_printf(seq, "%s ", pkt_dev->odev->name);
L
Linus Torvalds 已提交
1669

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

1672
	list_for_each_entry(pkt_dev, &t->if_list, list)
L
Luiz Capitulino 已提交
1673
		if (!pkt_dev->running)
1674
			seq_printf(seq, "%s ", pkt_dev->odev->name);
L
Linus Torvalds 已提交
1675 1676

	if (t->result[0])
1677
		seq_printf(seq, "\nResult: %s\n", t->result);
L
Linus Torvalds 已提交
1678
	else
1679
		seq_printf(seq, "\nResult: NA\n");
L
Linus Torvalds 已提交
1680

L
Luiz Capitulino 已提交
1681
	if_unlock(t);
L
Linus Torvalds 已提交
1682

1683
	return 0;
L
Linus Torvalds 已提交
1684 1685
}

1686
static ssize_t pktgen_thread_write(struct file *file,
L
Luiz Capitulino 已提交
1687 1688
				   const char __user * user_buffer,
				   size_t count, loff_t * offset)
L
Linus Torvalds 已提交
1689
{
L
Luiz Capitulino 已提交
1690 1691
	struct seq_file *seq = (struct seq_file *)file->private_data;
	struct pktgen_thread *t = seq->private;
L
Linus Torvalds 已提交
1692 1693
	int i = 0, max, len, ret;
	char name[40];
L
Luiz Capitulino 已提交
1694
	char *pg_result;
1695

L
Linus Torvalds 已提交
1696
	if (count < 1) {
L
Luiz Capitulino 已提交
1697
		//      sprintf(pg_result, "Wrong command format");
L
Linus Torvalds 已提交
1698 1699
		return -EINVAL;
	}
1700

L
Linus Torvalds 已提交
1701
	max = count - i;
L
Luiz Capitulino 已提交
1702 1703
	len = count_trail_chars(&user_buffer[i], max);
	if (len < 0)
1704 1705
		return len;

L
Linus Torvalds 已提交
1706
	i += len;
1707

L
Linus Torvalds 已提交
1708 1709 1710
	/* Read variable name */

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

L
Linus Torvalds 已提交
1714 1715 1716 1717
	memset(name, 0, sizeof(name));
	if (copy_from_user(name, &user_buffer[i], len))
		return -EFAULT;
	i += len;
1718

L
Luiz Capitulino 已提交
1719
	max = count - i;
L
Linus Torvalds 已提交
1720
	len = count_trail_chars(&user_buffer[i], max);
L
Luiz Capitulino 已提交
1721
	if (len < 0)
1722 1723
		return len;

L
Linus Torvalds 已提交
1724 1725
	i += len;

1726
	if (debug)
1727 1728
		printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n",
		       name, (unsigned long)count);
L
Linus Torvalds 已提交
1729

L
Luiz Capitulino 已提交
1730
	if (!t) {
1731
		printk(KERN_ERR "pktgen: ERROR: No thread\n");
L
Linus Torvalds 已提交
1732 1733 1734 1735 1736 1737
		ret = -EINVAL;
		goto out;
	}

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

L
Luiz Capitulino 已提交
1738 1739 1740
	if (!strcmp(name, "add_device")) {
		char f[32];
		memset(f, 0, 32);
L
Linus Torvalds 已提交
1741
		len = strn_len(&user_buffer[i], sizeof(f) - 1);
L
Luiz Capitulino 已提交
1742 1743
		if (len < 0) {
			ret = len;
L
Linus Torvalds 已提交
1744 1745
			goto out;
		}
L
Luiz Capitulino 已提交
1746
		if (copy_from_user(f, &user_buffer[i], len))
L
Linus Torvalds 已提交
1747 1748
			return -EFAULT;
		i += len;
1749
		mutex_lock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1750
		pktgen_add_device(t, f);
1751
		mutex_unlock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1752 1753
		ret = count;
		sprintf(pg_result, "OK: add_device=%s", f);
L
Linus Torvalds 已提交
1754 1755 1756
		goto out;
	}

L
Luiz Capitulino 已提交
1757
	if (!strcmp(name, "rem_device_all")) {
1758
		mutex_lock(&pktgen_thread_lock);
1759
		t->control |= T_REMDEVALL;
1760
		mutex_unlock(&pktgen_thread_lock);
L
Luiz Capitulino 已提交
1761
		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
L
Linus Torvalds 已提交
1762
		ret = count;
L
Luiz Capitulino 已提交
1763
		sprintf(pg_result, "OK: rem_device_all");
L
Linus Torvalds 已提交
1764 1765 1766
		goto out;
	}

L
Luiz Capitulino 已提交
1767
	if (!strcmp(name, "max_before_softirq")) {
1768
		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
L
Luiz Capitulino 已提交
1769
		ret = count;
L
Linus Torvalds 已提交
1770 1771 1772 1773
		goto out;
	}

	ret = -EINVAL;
L
Luiz Capitulino 已提交
1774
out:
L
Linus Torvalds 已提交
1775 1776 1777
	return ret;
}

1778
static int pktgen_thread_open(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
1779
{
1780
	return single_open(file, pktgen_thread_show, PDE(inode)->data);
L
Linus Torvalds 已提交
1781 1782
}

1783
static const struct file_operations pktgen_thread_fops = {
L
Luiz Capitulino 已提交
1784 1785 1786 1787 1788 1789
	.owner   = THIS_MODULE,
	.open    = pktgen_thread_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pktgen_thread_write,
	.release = single_release,
1790
};
L
Linus Torvalds 已提交
1791 1792

/* Think find or remove for NN */
L
Luiz Capitulino 已提交
1793
static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
L
Linus Torvalds 已提交
1794 1795 1796 1797
{
	struct pktgen_thread *t;
	struct pktgen_dev *pkt_dev = NULL;

1798
	list_for_each_entry(t, &pktgen_threads, th_list) {
L
Linus Torvalds 已提交
1799 1800
		pkt_dev = pktgen_find_dev(t, ifname);
		if (pkt_dev) {
L
Luiz Capitulino 已提交
1801 1802 1803 1804 1805 1806
			if (remove) {
				if_lock(t);
				pkt_dev->removal_mark = 1;
				t->control |= T_REMDEV;
				if_unlock(t);
			}
L
Linus Torvalds 已提交
1807 1808 1809
			break;
		}
	}
L
Luiz Capitulino 已提交
1810
	return pkt_dev;
L
Linus Torvalds 已提交
1811 1812
}

1813 1814 1815
/*
 * mark a device for removal
 */
1816
static void pktgen_mark_device(const char *ifname)
L
Linus Torvalds 已提交
1817 1818
{
	struct pktgen_dev *pkt_dev = NULL;
1819 1820 1821
	const int max_tries = 10, msec_per_try = 125;
	int i = 0;

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

L
Luiz Capitulino 已提交
1825
	while (1) {
1826 1827

		pkt_dev = __pktgen_NN_threads(ifname, REMOVE);
L
Luiz Capitulino 已提交
1828 1829
		if (pkt_dev == NULL)
			break;	/* success */
1830

1831
		mutex_unlock(&pktgen_thread_lock);
S
Stephen Hemminger 已提交
1832 1833
		pr_debug("pktgen: pktgen_mark_device waiting for %s "
				"to disappear....\n", ifname);
1834
		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
1835
		mutex_lock(&pktgen_thread_lock);
1836 1837

		if (++i >= max_tries) {
1838 1839
			printk(KERN_ERR "pktgen_mark_device: timed out after "
			       "waiting %d msec for device %s to be removed\n",
L
Luiz Capitulino 已提交
1840
			       msec_per_try * i, ifname);
1841 1842 1843 1844 1845
			break;
		}

	}

1846
	mutex_unlock(&pktgen_thread_lock);
1847
}
1848

1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
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 已提交
1870 1871
}

L
Luiz Capitulino 已提交
1872 1873
static int pktgen_device_event(struct notifier_block *unused,
			       unsigned long event, void *ptr)
L
Linus Torvalds 已提交
1874
{
1875
	struct net_device *dev = ptr;
L
Linus Torvalds 已提交
1876

1877
	if (dev_net(dev) != &init_net)
1878 1879
		return NOTIFY_DONE;

L
Linus Torvalds 已提交
1880 1881 1882 1883 1884
	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
1885 1886
	case NETDEV_CHANGENAME:
		pktgen_change_name(dev);
L
Linus Torvalds 已提交
1887
		break;
L
Luiz Capitulino 已提交
1888

L
Linus Torvalds 已提交
1889
	case NETDEV_UNREGISTER:
L
Luiz Capitulino 已提交
1890
		pktgen_mark_device(dev->name);
L
Linus Torvalds 已提交
1891
		break;
1892
	}
L
Linus Torvalds 已提交
1893 1894 1895 1896 1897 1898

	return NOTIFY_DONE;
}

/* Associate pktgen_dev with a device. */

1899
static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
L
Luiz Capitulino 已提交
1900
{
L
Linus Torvalds 已提交
1901
	struct net_device *odev;
1902
	int err;
L
Linus Torvalds 已提交
1903 1904 1905 1906

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

1910
	odev = dev_get_by_name(&init_net, ifname);
L
Linus Torvalds 已提交
1911
	if (!odev) {
1912
		printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname);
1913
		return -ENODEV;
L
Linus Torvalds 已提交
1914
	}
1915

L
Linus Torvalds 已提交
1916
	if (odev->type != ARPHRD_ETHER) {
1917
		printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname);
1918 1919
		err = -EINVAL;
	} else if (!netif_running(odev)) {
1920
		printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname);
1921 1922 1923 1924
		err = -ENETDOWN;
	} else {
		pkt_dev->odev = odev;
		return 0;
L
Linus Torvalds 已提交
1925 1926 1927
	}

	dev_put(odev);
1928
	return err;
L
Linus Torvalds 已提交
1929 1930 1931 1932 1933 1934 1935
}

/* 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 已提交
1936
	if (!pkt_dev->odev) {
1937 1938
		printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
		       "setup_inject.\n");
L
Luiz Capitulino 已提交
1939 1940 1941 1942 1943 1944
		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 已提交
1945

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

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

L
Luiz Capitulino 已提交
1952 1953 1954 1955
	/* Set up pkt size */
	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;

	if (pkt_dev->flags & F_IPV6) {
L
Linus Torvalds 已提交
1956
		/*
1957
		 * Skip this automatic address setting until locks or functions
L
Linus Torvalds 已提交
1958 1959 1960 1961
		 * gets exported
		 */

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

L
Luiz Capitulino 已提交
1965 1966
		for (i = 0; i < IN6_ADDR_HSIZE; i++)
			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
L
Linus Torvalds 已提交
1967 1968 1969 1970
				set = 1;
				break;
			}

L
Luiz Capitulino 已提交
1971 1972
		if (!set) {

L
Linus Torvalds 已提交
1973 1974 1975 1976 1977 1978
			/*
			 * Use linklevel address if unconfigured.
			 *
			 * use ipv6_get_lladdr if/when it's get exported
			 */

1979
			rcu_read_lock();
L
Linus Torvalds 已提交
1980 1981 1982 1983
			if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) {
				struct inet6_ifaddr *ifp;

				read_lock_bh(&idev->lock);
L
Luiz Capitulino 已提交
1984 1985 1986 1987 1988 1989 1990 1991
				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 已提交
1992 1993 1994 1995 1996 1997
						err = 0;
						break;
					}
				}
				read_unlock_bh(&idev->lock);
			}
1998
			rcu_read_unlock();
L
Luiz Capitulino 已提交
1999
			if (err)
2000 2001
				printk(KERN_ERR "pktgen: ERROR: IPv6 link "
				       "address not availble.\n");
L
Linus Torvalds 已提交
2002 2003
		}
#endif
L
Luiz Capitulino 已提交
2004
	} else {
L
Linus Torvalds 已提交
2005 2006 2007
		pkt_dev->saddr_min = 0;
		pkt_dev->saddr_max = 0;
		if (strlen(pkt_dev->src_min) == 0) {
L
Luiz Capitulino 已提交
2008 2009

			struct in_device *in_dev;
L
Linus Torvalds 已提交
2010 2011

			rcu_read_lock();
2012
			in_dev = __in_dev_get_rcu(pkt_dev->odev);
L
Linus Torvalds 已提交
2013 2014
			if (in_dev) {
				if (in_dev->ifa_list) {
L
Luiz Capitulino 已提交
2015 2016
					pkt_dev->saddr_min =
					    in_dev->ifa_list->ifa_address;
L
Linus Torvalds 已提交
2017 2018 2019 2020
					pkt_dev->saddr_max = pkt_dev->saddr_min;
				}
			}
			rcu_read_unlock();
L
Luiz Capitulino 已提交
2021
		} else {
L
Linus Torvalds 已提交
2022 2023 2024 2025 2026 2027 2028
			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 已提交
2029 2030 2031 2032 2033 2034 2035
	/* 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 已提交
2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
	pkt_dev->nflows = 0;
}

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

	start = now = getCurUs();
	while (now < spin_until_us) {
2046
		/* TODO: optimize sleeping behavior */
L
Luiz Capitulino 已提交
2047
		if (spin_until_us - now > jiffies_to_usecs(1) + 1)
2048 2049
			schedule_timeout_interruptible(1);
		else if (spin_until_us - now > 100) {
L
Linus Torvalds 已提交
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
			if (!pkt_dev->running)
				return;
			if (need_resched())
				schedule();
		}

		now = getCurUs();
	}

	pkt_dev->idle_acc += now - start;
}

2062 2063
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
{
J
Jamal Hadi Salim 已提交
2064
	pkt_dev->pkt_overhead = 0;
2065 2066 2067 2068 2069
	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);
}

2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
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 已提交
2101 2102 2103 2104 2105

#ifdef CONFIG_XFRM
/* If there was already an IPSEC SA, we keep it as is, else
 * we go look for it ...
*/
2106
static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
J
Jamal Hadi Salim 已提交
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124
{
	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 已提交
2125 2126 2127
/* Increment/randomize headers according to flags and current values
 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
 */
L
Luiz Capitulino 已提交
2128 2129 2130 2131 2132
static void mod_cur_headers(struct pktgen_dev *pkt_dev)
{
	__u32 imn;
	__u32 imx;
	int flow = 0;
L
Linus Torvalds 已提交
2133

2134 2135
	if (pkt_dev->cflows)
		flow = f_pick(pkt_dev);
L
Linus Torvalds 已提交
2136 2137

	/*  Deal with source MAC */
L
Luiz Capitulino 已提交
2138 2139 2140 2141 2142
	if (pkt_dev->src_mac_count > 1) {
		__u32 mc;
		__u32 tmp;

		if (pkt_dev->flags & F_MACSRC_RND)
S
Stephen Hemminger 已提交
2143
			mc = random32() % pkt_dev->src_mac_count;
L
Luiz Capitulino 已提交
2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
		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 已提交
2169
			mc = random32() % pkt_dev->dst_mac_count;
L
Luiz Capitulino 已提交
2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190

		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;
	}

2191 2192
	if (pkt_dev->flags & F_MPLS_RND) {
		unsigned i;
2193
		for (i = 0; i < pkt_dev->nr_labels; i++)
2194 2195
			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
S
Stephen Hemminger 已提交
2196
					     ((__force __be32)random32() &
2197 2198 2199
						      htonl(0x000fffff));
	}

F
Francesco Fondelli 已提交
2200
	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
S
Stephen Hemminger 已提交
2201
		pkt_dev->vlan_id = random32() & (4096-1);
F
Francesco Fondelli 已提交
2202 2203 2204
	}

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

L
Luiz Capitulino 已提交
2208 2209
	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
		if (pkt_dev->flags & F_UDPSRC_RND)
S
Stephen Hemminger 已提交
2210 2211 2212
			pkt_dev->cur_udp_src = random32() %
				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
				+ pkt_dev->udp_src_min;
L
Luiz Capitulino 已提交
2213 2214

		else {
L
Linus Torvalds 已提交
2215 2216 2217
			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 已提交
2218 2219 2220 2221 2222
		}
	}

	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
		if (pkt_dev->flags & F_UDPDST_RND) {
S
Stephen Hemminger 已提交
2223 2224 2225
			pkt_dev->cur_udp_dst = random32() %
				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
				+ pkt_dev->udp_dst_min;
L
Luiz Capitulino 已提交
2226
		} else {
L
Linus Torvalds 已提交
2227
			pkt_dev->cur_udp_dst++;
L
Luiz Capitulino 已提交
2228
			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
L
Linus Torvalds 已提交
2229
				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
L
Luiz Capitulino 已提交
2230 2231
		}
	}
L
Linus Torvalds 已提交
2232 2233 2234

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

L
Luiz Capitulino 已提交
2235 2236 2237
		if ((imn = ntohl(pkt_dev->saddr_min)) < (imx =
							 ntohl(pkt_dev->
							       saddr_max))) {
L
Linus Torvalds 已提交
2238
			__u32 t;
L
Luiz Capitulino 已提交
2239
			if (pkt_dev->flags & F_IPSRC_RND)
S
Stephen Hemminger 已提交
2240
				t = random32() % (imx - imn) + imn;
L
Linus Torvalds 已提交
2241 2242 2243 2244 2245 2246 2247 2248 2249
			else {
				t = ntohl(pkt_dev->cur_saddr);
				t++;
				if (t > imx) {
					t = imn;
				}
			}
			pkt_dev->cur_saddr = htonl(t);
		}
L
Luiz Capitulino 已提交
2250

2251
		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
L
Linus Torvalds 已提交
2252 2253
			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
		} else {
A
Al Viro 已提交
2254 2255 2256
			imn = ntohl(pkt_dev->daddr_min);
			imx = ntohl(pkt_dev->daddr_max);
			if (imn < imx) {
L
Linus Torvalds 已提交
2257
				__u32 t;
A
Al Viro 已提交
2258
				__be32 s;
L
Linus Torvalds 已提交
2259 2260
				if (pkt_dev->flags & F_IPDST_RND) {

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

2264 2265
					while (ipv4_is_loopback(s) ||
					       ipv4_is_multicast(s) ||
2266
					       ipv4_is_lbcast(s) ||
2267 2268
					       ipv4_is_zeronet(s) ||
					       ipv4_is_local_multicast(s)) {
S
Stephen Hemminger 已提交
2269
						t = random32() % (imx - imn) + imn;
A
Al Viro 已提交
2270
						s = htonl(t);
L
Linus Torvalds 已提交
2271
					}
A
Al Viro 已提交
2272 2273
					pkt_dev->cur_daddr = s;
				} else {
L
Linus Torvalds 已提交
2274 2275 2276 2277 2278 2279 2280 2281
					t = ntohl(pkt_dev->cur_daddr);
					t++;
					if (t > imx) {
						t = imn;
					}
					pkt_dev->cur_daddr = htonl(t);
				}
			}
L
Luiz Capitulino 已提交
2282
			if (pkt_dev->cflows) {
2283
				pkt_dev->flows[flow].flags |= F_INIT;
L
Luiz Capitulino 已提交
2284 2285
				pkt_dev->flows[flow].cur_daddr =
				    pkt_dev->cur_daddr;
J
Jamal Hadi Salim 已提交
2286 2287 2288 2289
#ifdef CONFIG_XFRM
				if (pkt_dev->flags & F_IPSEC_ON)
					get_ipsec_sa(pkt_dev, flow);
#endif
L
Linus Torvalds 已提交
2290 2291 2292
				pkt_dev->nflows++;
			}
		}
L
Luiz Capitulino 已提交
2293 2294 2295 2296 2297 2298
	} 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 已提交
2299 2300 2301 2302 2303
		else {
			int i;

			/* Only random destinations yet */

L
Luiz Capitulino 已提交
2304
			for (i = 0; i < 4; i++) {
L
Linus Torvalds 已提交
2305
				pkt_dev->cur_in6_daddr.s6_addr32[i] =
S
Stephen Hemminger 已提交
2306
				    (((__force __be32)random32() |
L
Luiz Capitulino 已提交
2307 2308
				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
				     pkt_dev->max_in6_daddr.s6_addr32[i]);
L
Linus Torvalds 已提交
2309
			}
L
Luiz Capitulino 已提交
2310
		}
L
Linus Torvalds 已提交
2311 2312
	}

L
Luiz Capitulino 已提交
2313 2314 2315
	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
		__u32 t;
		if (pkt_dev->flags & F_TXSIZE_RND) {
S
Stephen Hemminger 已提交
2316 2317 2318
			t = random32() %
				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
				+ pkt_dev->min_pkt_size;
L
Luiz Capitulino 已提交
2319
		} else {
L
Linus Torvalds 已提交
2320
			t = pkt_dev->cur_pkt_size + 1;
L
Luiz Capitulino 已提交
2321
			if (t > pkt_dev->max_pkt_size)
L
Linus Torvalds 已提交
2322
				t = pkt_dev->min_pkt_size;
L
Luiz Capitulino 已提交
2323 2324 2325
		}
		pkt_dev->cur_pkt_size = t;
	}
L
Linus Torvalds 已提交
2326

R
Robert Olsson 已提交
2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
	if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) {
		__u16 t;
		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
			t = random32() %
				(pkt_dev->queue_map_max - pkt_dev->queue_map_min + 1)
				+ pkt_dev->queue_map_min;
		} else {
			t = pkt_dev->cur_queue_map + 1;
			if (t > pkt_dev->queue_map_max)
				t = pkt_dev->queue_map_min;
		}
		pkt_dev->cur_queue_map = t;
	}

L
Linus Torvalds 已提交
2341 2342 2343
	pkt_dev->flows[flow].count++;
}

J
Jamal Hadi Salim 已提交
2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361

#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);

2362
	err = x->outer_mode->output(x, skb);
J
Jamal Hadi Salim 已提交
2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403
	if (err)
		goto error;
	err = x->type->output(x, skb);
	if (err)
		goto error;

	x->curlft.bytes +=skb->len;
	x->curlft.packets++;
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) {
2404 2405
					printk(KERN_ERR "Error expanding "
					       "ipsec packet %d\n",ret);
J
Jamal Hadi Salim 已提交
2406 2407 2408 2409 2410 2411 2412 2413
					return 0;
				}
			}

			/* ipsec is not expecting ll header */
			skb_pull(skb, ETH_HLEN);
			ret = pktgen_output_ipsec(skb, pkt_dev);
			if (ret) {
2414 2415
				printk(KERN_ERR "Error creating ipsec "
				       "packet %d\n",ret);
J
Jamal Hadi Salim 已提交
2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
				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

2429 2430 2431
static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
	unsigned i;
2432
	for (i = 0; i < pkt_dev->nr_labels; i++) {
2433 2434 2435 2436 2437 2438
		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
	}
	mpls--;
	*mpls |= MPLS_STACK_BOTTOM;
}

A
Al Viro 已提交
2439 2440 2441 2442 2443 2444
static inline __be16 build_tci(unsigned int id, unsigned int cfi,
			       unsigned int prio)
{
	return htons(id | (cfi << 12) | (prio << 13));
}

L
Luiz Capitulino 已提交
2445 2446
static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
					struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
2447 2448 2449 2450 2451 2452
{
	struct sk_buff *skb = NULL;
	__u8 *eth;
	struct udphdr *udph;
	int datalen, iplen;
	struct iphdr *iph;
L
Luiz Capitulino 已提交
2453
	struct pktgen_hdr *pgh = NULL;
2454
	__be16 protocol = htons(ETH_P_IP);
2455
	__be32 *mpls;
F
Francesco Fondelli 已提交
2456 2457 2458 2459 2460
	__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 */

2461 2462

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

F
Francesco Fondelli 已提交
2465
	if (pkt_dev->vlan_id != 0xffff)
2466
		protocol = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2467

2468 2469 2470 2471 2472
	/* Update any of the values, used when we're incrementing various
	 * fields.
	 */
	mod_cur_headers(pkt_dev);

2473
	datalen = (odev->hard_header_len + 16) & ~0xf;
2474
	skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
2475
			pkt_dev->pkt_overhead, GFP_ATOMIC);
L
Linus Torvalds 已提交
2476 2477 2478 2479 2480
	if (!skb) {
		sprintf(pkt_dev->result, "No memory");
		return NULL;
	}

2481
	skb_reserve(skb, datalen);
L
Linus Torvalds 已提交
2482 2483 2484

	/*  Reserve for ethernet and IP header  */
	eth = (__u8 *) skb_push(skb, 14);
2485 2486 2487
	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
	if (pkt_dev->nr_labels)
		mpls_push(mpls, pkt_dev);
F
Francesco Fondelli 已提交
2488 2489

	if (pkt_dev->vlan_id != 0xffff) {
2490
		if (pkt_dev->svlan_id != 0xffff) {
F
Francesco Fondelli 已提交
2491
			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2492 2493 2494
			*svlan_tci = build_tci(pkt_dev->svlan_id,
					       pkt_dev->svlan_cfi,
					       pkt_dev->svlan_p);
F
Francesco Fondelli 已提交
2495
			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2496
			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2497 2498
		}
		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2499 2500 2501
		*vlan_tci = build_tci(pkt_dev->vlan_id,
				      pkt_dev->vlan_cfi,
				      pkt_dev->vlan_p);
F
Francesco Fondelli 已提交
2502
		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2503
		*vlan_encapsulated_proto = htons(ETH_P_IP);
F
Francesco Fondelli 已提交
2504 2505
	}

2506
	skb->network_header = skb->tail;
2507
	skb->transport_header = skb->network_header + sizeof(struct iphdr);
2508
	skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
2509
	skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
2510 2511
	iph = ip_hdr(skb);
	udph = udp_hdr(skb);
L
Linus Torvalds 已提交
2512 2513

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

2516 2517
	/* Eth + IPh + UDPh + mpls */
	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
2518
		  pkt_dev->pkt_overhead;
L
Luiz Capitulino 已提交
2519
	if (datalen < sizeof(struct pktgen_hdr))
L
Linus Torvalds 已提交
2520
		datalen = sizeof(struct pktgen_hdr);
L
Luiz Capitulino 已提交
2521

L
Linus Torvalds 已提交
2522 2523
	udph->source = htons(pkt_dev->cur_udp_src);
	udph->dest = htons(pkt_dev->cur_udp_dst);
L
Luiz Capitulino 已提交
2524 2525
	udph->len = htons(datalen + 8);	/* DATA + udphdr */
	udph->check = 0;	/* No checksum */
L
Linus Torvalds 已提交
2526 2527 2528 2529

	iph->ihl = 5;
	iph->version = 4;
	iph->ttl = 32;
F
Francesco Fondelli 已提交
2530
	iph->tos = pkt_dev->tos;
L
Luiz Capitulino 已提交
2531
	iph->protocol = IPPROTO_UDP;	/* UDP */
L
Linus Torvalds 已提交
2532 2533 2534 2535 2536 2537
	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 已提交
2538
	iph->check = ip_fast_csum((void *)iph, iph->ihl);
2539
	skb->protocol = protocol;
2540
	skb->mac_header = (skb->network_header - ETH_HLEN -
2541
			   pkt_dev->pkt_overhead);
L
Linus Torvalds 已提交
2542 2543 2544
	skb->dev = odev;
	skb->pkt_type = PACKET_HOST;

L
Luiz Capitulino 已提交
2545 2546
	if (pkt_dev->nfrags <= 0)
		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
L
Linus Torvalds 已提交
2547 2548 2549 2550
	else {
		int frags = pkt_dev->nfrags;
		int i;

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

L
Linus Torvalds 已提交
2553 2554
		if (frags > MAX_SKB_FRAGS)
			frags = MAX_SKB_FRAGS;
L
Luiz Capitulino 已提交
2555 2556 2557
		if (datalen > frags * PAGE_SIZE) {
			skb_put(skb, datalen - frags * PAGE_SIZE);
			datalen = frags * PAGE_SIZE;
L
Linus Torvalds 已提交
2558 2559 2560 2561 2562 2563 2564 2565
		}

		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 已提交
2566
			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
L
Linus Torvalds 已提交
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585
			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 已提交
2586 2587
			skb_shinfo(skb)->frags[i] =
			    skb_shinfo(skb)->frags[i - 1];
L
Linus Torvalds 已提交
2588
			get_page(skb_shinfo(skb)->frags[i].page);
L
Luiz Capitulino 已提交
2589 2590 2591 2592
			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 已提交
2593 2594 2595 2596 2597 2598
			skb_shinfo(skb)->frags[i].size = rem;
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}
	}

L
Luiz Capitulino 已提交
2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610
	/* 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 已提交
2611

J
Jamal Hadi Salim 已提交
2612 2613 2614 2615 2616
#ifdef CONFIG_XFRM
	if (!process_ipsec(pkt_dev, skb, protocol))
		return NULL;
#endif

L
Linus Torvalds 已提交
2617 2618 2619 2620
	return skb;
}

/*
2621
 * scan_ip6, fmt_ip taken from dietlibc-0.21
L
Linus Torvalds 已提交
2622 2623
 * Author Felix von Leitner <felix-dietlibc@fefe.de>
 *
2624
 * Slightly modified for kernel.
L
Linus Torvalds 已提交
2625 2626 2627 2628
 * Should be candidate for net/ipv4/utils.c
 * --ro
 */

L
Luiz Capitulino 已提交
2629
static unsigned int scan_ip6(const char *s, char ip[16])
L
Linus Torvalds 已提交
2630 2631
{
	unsigned int i;
L
Luiz Capitulino 已提交
2632
	unsigned int len = 0;
L
Linus Torvalds 已提交
2633 2634
	unsigned long u;
	char suffix[16];
L
Luiz Capitulino 已提交
2635 2636
	unsigned int prefixlen = 0;
	unsigned int suffixlen = 0;
A
Al Viro 已提交
2637
	__be32 tmp;
S
Stephen Hemminger 已提交
2638
	char *pos;
L
Linus Torvalds 已提交
2639

L
Luiz Capitulino 已提交
2640 2641
	for (i = 0; i < 16; i++)
		ip[i] = 0;
L
Linus Torvalds 已提交
2642 2643 2644 2645

	for (;;) {
		if (*s == ':') {
			len++;
L
Luiz Capitulino 已提交
2646 2647
			if (s[1] == ':') {	/* Found "::", skip to part 2 */
				s += 2;
L
Linus Torvalds 已提交
2648 2649 2650 2651 2652 2653
				len++;
				break;
			}
			s++;
		}

S
Stephen Hemminger 已提交
2654 2655
		u = simple_strtoul(s, &pos, 16);
		i = pos - s;
L
Luiz Capitulino 已提交
2656 2657 2658
		if (!i)
			return 0;
		if (prefixlen == 12 && s[i] == '.') {
L
Linus Torvalds 已提交
2659 2660 2661 2662

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

			tmp = in_aton(s);
L
Luiz Capitulino 已提交
2663 2664
			memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp));
			return i + len;
L
Linus Torvalds 已提交
2665 2666 2667
		}
		ip[prefixlen++] = (u >> 8);
		ip[prefixlen++] = (u & 255);
L
Luiz Capitulino 已提交
2668 2669 2670
		s += i;
		len += i;
		if (prefixlen == 16)
L
Linus Torvalds 已提交
2671 2672 2673 2674 2675 2676
			return len;
	}

/* part 2, after "::" */
	for (;;) {
		if (*s == ':') {
L
Luiz Capitulino 已提交
2677
			if (suffixlen == 0)
L
Linus Torvalds 已提交
2678 2679 2680
				break;
			s++;
			len++;
L
Luiz Capitulino 已提交
2681
		} else if (suffixlen != 0)
L
Linus Torvalds 已提交
2682
			break;
S
Stephen Hemminger 已提交
2683 2684 2685

		u = simple_strtol(s, &pos, 16);
		i = pos - s;
L
Linus Torvalds 已提交
2686
		if (!i) {
L
Luiz Capitulino 已提交
2687 2688
			if (*s)
				len--;
L
Linus Torvalds 已提交
2689 2690
			break;
		}
L
Luiz Capitulino 已提交
2691
		if (suffixlen + prefixlen <= 12 && s[i] == '.') {
L
Linus Torvalds 已提交
2692
			tmp = in_aton(s);
L
Luiz Capitulino 已提交
2693 2694 2695 2696
			memcpy((struct in_addr *)(suffix + suffixlen), &tmp,
			       sizeof(tmp));
			suffixlen += 4;
			len += strlen(s);
L
Linus Torvalds 已提交
2697 2698 2699 2700
			break;
		}
		suffix[suffixlen++] = (u >> 8);
		suffix[suffixlen++] = (u & 255);
L
Luiz Capitulino 已提交
2701 2702 2703
		s += i;
		len += i;
		if (prefixlen + suffixlen == 16)
L
Linus Torvalds 已提交
2704 2705
			break;
	}
L
Luiz Capitulino 已提交
2706 2707
	for (i = 0; i < suffixlen; i++)
		ip[16 - suffixlen + i] = suffix[i];
L
Linus Torvalds 已提交
2708 2709 2710
	return len;
}

L
Luiz Capitulino 已提交
2711 2712 2713
static char tohex(char hexdigit)
{
	return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
L
Linus Torvalds 已提交
2714 2715
}

L
Luiz Capitulino 已提交
2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
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 已提交
2730 2731
}

L
Luiz Capitulino 已提交
2732 2733
static unsigned int fmt_ip6(char *s, const char ip[16])
{
L
Linus Torvalds 已提交
2734 2735 2736 2737 2738 2739
	unsigned int len;
	unsigned int i;
	unsigned int temp;
	unsigned int compressing;
	int j;

L
Luiz Capitulino 已提交
2740 2741 2742
	len = 0;
	compressing = 0;
	for (j = 0; j < 16; j += 2) {
L
Linus Torvalds 已提交
2743 2744

#ifdef V4MAPPEDPREFIX
L
Luiz Capitulino 已提交
2745 2746 2747 2748
		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 已提交
2749 2750
		}
#endif
L
Luiz Capitulino 已提交
2751 2752
		temp = ((unsigned long)(unsigned char)ip[j] << 8) +
		    (unsigned long)(unsigned char)ip[j + 1];
L
Linus Torvalds 已提交
2753 2754
		if (temp == 0) {
			if (!compressing) {
L
Luiz Capitulino 已提交
2755 2756 2757 2758
				compressing = 1;
				if (j == 0) {
					*s++ = ':';
					++len;
L
Linus Torvalds 已提交
2759 2760 2761 2762
				}
			}
		} else {
			if (compressing) {
L
Luiz Capitulino 已提交
2763 2764 2765
				compressing = 0;
				*s++ = ':';
				++len;
L
Linus Torvalds 已提交
2766
			}
L
Luiz Capitulino 已提交
2767 2768 2769 2770
			i = fmt_xlong(s, temp);
			len += i;
			s += i;
			if (j < 14) {
L
Linus Torvalds 已提交
2771 2772 2773 2774 2775 2776
				*s++ = ':';
				++len;
			}
		}
	}
	if (compressing) {
L
Luiz Capitulino 已提交
2777 2778
		*s++ = ':';
		++len;
L
Linus Torvalds 已提交
2779
	}
L
Luiz Capitulino 已提交
2780
	*s = 0;
L
Linus Torvalds 已提交
2781 2782 2783
	return len;
}

L
Luiz Capitulino 已提交
2784 2785
static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
					struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
2786 2787 2788 2789 2790 2791
{
	struct sk_buff *skb = NULL;
	__u8 *eth;
	struct udphdr *udph;
	int datalen;
	struct ipv6hdr *iph;
L
Luiz Capitulino 已提交
2792
	struct pktgen_hdr *pgh = NULL;
2793
	__be16 protocol = htons(ETH_P_IPV6);
2794
	__be32 *mpls;
F
Francesco Fondelli 已提交
2795 2796 2797 2798
	__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 */
2799 2800

	if (pkt_dev->nr_labels)
2801
		protocol = htons(ETH_P_MPLS_UC);
2802

F
Francesco Fondelli 已提交
2803
	if (pkt_dev->vlan_id != 0xffff)
2804
		protocol = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2805

2806 2807 2808 2809 2810
	/* Update any of the values, used when we're incrementing various
	 * fields.
	 */
	mod_cur_headers(pkt_dev);

2811
	skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
2812
			pkt_dev->pkt_overhead, GFP_ATOMIC);
L
Linus Torvalds 已提交
2813 2814 2815 2816 2817 2818 2819 2820 2821
	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);
2822 2823 2824
	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
	if (pkt_dev->nr_labels)
		mpls_push(mpls, pkt_dev);
F
Francesco Fondelli 已提交
2825 2826

	if (pkt_dev->vlan_id != 0xffff) {
2827
		if (pkt_dev->svlan_id != 0xffff) {
F
Francesco Fondelli 已提交
2828
			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2829 2830 2831
			*svlan_tci = build_tci(pkt_dev->svlan_id,
					       pkt_dev->svlan_cfi,
					       pkt_dev->svlan_p);
F
Francesco Fondelli 已提交
2832
			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2833
			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
F
Francesco Fondelli 已提交
2834 2835
		}
		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
A
Al Viro 已提交
2836 2837 2838
		*vlan_tci = build_tci(pkt_dev->vlan_id,
				      pkt_dev->vlan_cfi,
				      pkt_dev->vlan_p);
F
Francesco Fondelli 已提交
2839
		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2840
		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
F
Francesco Fondelli 已提交
2841 2842
	}

2843
	skb->network_header = skb->tail;
2844
	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
2845
	skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
2846
	skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
2847 2848
	iph = ipv6_hdr(skb);
	udph = udp_hdr(skb);
L
Linus Torvalds 已提交
2849 2850

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

2853 2854 2855
	/* Eth + IPh + UDPh + mpls */
	datalen = pkt_dev->cur_pkt_size - 14 -
		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
2856
		  pkt_dev->pkt_overhead;
L
Linus Torvalds 已提交
2857

L
Luiz Capitulino 已提交
2858
	if (datalen < sizeof(struct pktgen_hdr)) {
L
Linus Torvalds 已提交
2859 2860
		datalen = sizeof(struct pktgen_hdr);
		if (net_ratelimit())
L
Luiz Capitulino 已提交
2861 2862
			printk(KERN_INFO "pktgen: increased datalen to %d\n",
			       datalen);
L
Linus Torvalds 已提交
2863 2864 2865 2866
	}

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

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

F
Francesco Fondelli 已提交
2872 2873
	if (pkt_dev->traffic_class) {
		/* Version + traffic class + flow (0) */
A
Al Viro 已提交
2874
		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
F
Francesco Fondelli 已提交
2875 2876
	}

L
Linus Torvalds 已提交
2877 2878 2879 2880 2881 2882 2883 2884
	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);

2885
	skb->mac_header = (skb->network_header - ETH_HLEN -
2886
			   pkt_dev->pkt_overhead);
2887
	skb->protocol = protocol;
L
Linus Torvalds 已提交
2888 2889 2890
	skb->dev = odev;
	skb->pkt_type = PACKET_HOST;

L
Luiz Capitulino 已提交
2891 2892
	if (pkt_dev->nfrags <= 0)
		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
L
Linus Torvalds 已提交
2893 2894 2895 2896
	else {
		int frags = pkt_dev->nfrags;
		int i;

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

L
Linus Torvalds 已提交
2899 2900
		if (frags > MAX_SKB_FRAGS)
			frags = MAX_SKB_FRAGS;
L
Luiz Capitulino 已提交
2901 2902 2903
		if (datalen > frags * PAGE_SIZE) {
			skb_put(skb, datalen - frags * PAGE_SIZE);
			datalen = frags * PAGE_SIZE;
L
Linus Torvalds 已提交
2904 2905 2906 2907 2908 2909 2910 2911
		}

		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 已提交
2912
			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
L
Linus Torvalds 已提交
2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931
			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 已提交
2932 2933
			skb_shinfo(skb)->frags[i] =
			    skb_shinfo(skb)->frags[i - 1];
L
Linus Torvalds 已提交
2934
			get_page(skb_shinfo(skb)->frags[i].page);
L
Luiz Capitulino 已提交
2935 2936 2937 2938
			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 已提交
2939 2940 2941 2942 2943 2944
			skb_shinfo(skb)->frags[i].size = rem;
			i++;
			skb_shinfo(skb)->nr_frags = i;
		}
	}

L
Luiz Capitulino 已提交
2945
	/* Stamp the time, and sequence number, convert them to network byte order */
L
Linus Torvalds 已提交
2946
	/* should we update cloned packets too ? */
L
Luiz Capitulino 已提交
2947 2948 2949 2950 2951 2952 2953 2954 2955 2956
	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 已提交
2957
	/* pkt_dev->seq_num++; FF: you really mean this? */
L
Luiz Capitulino 已提交
2958

L
Linus Torvalds 已提交
2959 2960 2961
	return skb;
}

L
Luiz Capitulino 已提交
2962 2963
static inline struct sk_buff *fill_packet(struct net_device *odev,
					  struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
2964
{
L
Luiz Capitulino 已提交
2965
	if (pkt_dev->flags & F_IPV6)
L
Linus Torvalds 已提交
2966 2967 2968 2969 2970
		return fill_packet_ipv6(odev, pkt_dev);
	else
		return fill_packet_ipv4(odev, pkt_dev);
}

L
Luiz Capitulino 已提交
2971
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
2972
{
L
Luiz Capitulino 已提交
2973 2974
	pkt_dev->seq_num = 1;
	pkt_dev->idle_acc = 0;
L
Linus Torvalds 已提交
2975
	pkt_dev->sofar = 0;
L
Luiz Capitulino 已提交
2976 2977
	pkt_dev->tx_bytes = 0;
	pkt_dev->errors = 0;
L
Linus Torvalds 已提交
2978 2979 2980 2981 2982 2983
}

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

static void pktgen_run(struct pktgen_thread *t)
{
2984
	struct pktgen_dev *pkt_dev;
L
Linus Torvalds 已提交
2985 2986
	int started = 0;

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

	if_lock(t);
2990
	list_for_each_entry(pkt_dev, &t->if_list, list) {
L
Linus Torvalds 已提交
2991 2992 2993 2994 2995 2996

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

L
Luiz Capitulino 已提交
2997
		if (pkt_dev->odev) {
L
Linus Torvalds 已提交
2998
			pktgen_clear_counters(pkt_dev);
L
Luiz Capitulino 已提交
2999
			pkt_dev->running = 1;	/* Cranke yeself! */
L
Linus Torvalds 已提交
3000 3001
			pkt_dev->skb = NULL;
			pkt_dev->started_at = getCurUs();
L
Luiz Capitulino 已提交
3002
			pkt_dev->next_tx_us = getCurUs();	/* Transmit immediately */
L
Linus Torvalds 已提交
3003
			pkt_dev->next_tx_ns = 0;
3004
			set_pkt_overhead(pkt_dev);
L
Luiz Capitulino 已提交
3005

L
Linus Torvalds 已提交
3006 3007
			strcpy(pkt_dev->result, "Starting");
			started++;
L
Luiz Capitulino 已提交
3008
		} else
L
Linus Torvalds 已提交
3009 3010 3011
			strcpy(pkt_dev->result, "Error starting");
	}
	if_unlock(t);
L
Luiz Capitulino 已提交
3012 3013
	if (started)
		t->control &= ~(T_STOP);
L
Linus Torvalds 已提交
3014 3015 3016 3017
}

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

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

3022
	mutex_lock(&pktgen_thread_lock);
3023 3024

	list_for_each_entry(t, &pktgen_threads, th_list)
3025
		t->control |= T_STOP;
3026

3027
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3028 3029
}

L
Luiz Capitulino 已提交
3030
static int thread_is_running(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3031
{
3032
	struct pktgen_dev *pkt_dev;
L
Luiz Capitulino 已提交
3033
	int res = 0;
L
Linus Torvalds 已提交
3034

3035 3036
	list_for_each_entry(pkt_dev, &t->if_list, list)
		if (pkt_dev->running) {
L
Linus Torvalds 已提交
3037 3038 3039
			res = 1;
			break;
		}
L
Luiz Capitulino 已提交
3040
	return res;
L
Linus Torvalds 已提交
3041 3042
}

L
Luiz Capitulino 已提交
3043
static int pktgen_wait_thread_run(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3044
{
L
Luiz Capitulino 已提交
3045
	if_lock(t);
L
Linus Torvalds 已提交
3046

L
Luiz Capitulino 已提交
3047
	while (thread_is_running(t)) {
L
Linus Torvalds 已提交
3048

L
Luiz Capitulino 已提交
3049
		if_unlock(t);
L
Linus Torvalds 已提交
3050

L
Luiz Capitulino 已提交
3051
		msleep_interruptible(100);
L
Linus Torvalds 已提交
3052

L
Luiz Capitulino 已提交
3053 3054 3055 3056 3057 3058 3059 3060
		if (signal_pending(current))
			goto signal;
		if_lock(t);
	}
	if_unlock(t);
	return 1;
signal:
	return 0;
L
Linus Torvalds 已提交
3061 3062 3063 3064
}

static int pktgen_wait_all_threads_run(void)
{
3065
	struct pktgen_thread *t;
L
Linus Torvalds 已提交
3066
	int sig = 1;
L
Luiz Capitulino 已提交
3067

3068
	mutex_lock(&pktgen_thread_lock);
3069 3070

	list_for_each_entry(t, &pktgen_threads, th_list) {
L
Linus Torvalds 已提交
3071
		sig = pktgen_wait_thread_run(t);
L
Luiz Capitulino 已提交
3072 3073
		if (sig == 0)
			break;
L
Linus Torvalds 已提交
3074
	}
3075 3076 3077

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

3080
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3081 3082 3083 3084 3085
	return sig;
}

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

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

3090
	mutex_lock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3091

3092
	list_for_each_entry(t, &pktgen_threads, th_list)
L
Linus Torvalds 已提交
3093
		t->control |= (T_RUN);
3094

3095
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3096

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

L
Linus Torvalds 已提交
3099 3100 3101 3102 3103
	pktgen_wait_all_threads_run();
}

static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
{
L
Luiz Capitulino 已提交
3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135
	__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 已提交
3136 3137 3138 3139
}

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

L
Luiz Capitulino 已提交
3140
static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3141
{
L
Luiz Capitulino 已提交
3142
	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
3143

L
Luiz Capitulino 已提交
3144
	if (!pkt_dev->running) {
3145 3146
		printk(KERN_WARNING "pktgen: interface: %s is already "
		       "stopped\n", pkt_dev->odev->name);
L
Luiz Capitulino 已提交
3147 3148
		return -EINVAL;
	}
L
Linus Torvalds 已提交
3149

L
Luiz Capitulino 已提交
3150 3151
	pkt_dev->stopped_at = getCurUs();
	pkt_dev->running = 0;
L
Linus Torvalds 已提交
3152

3153
	show_results(pkt_dev, nr_frags);
L
Linus Torvalds 已提交
3154

L
Luiz Capitulino 已提交
3155
	return 0;
L
Linus Torvalds 已提交
3156 3157
}

L
Luiz Capitulino 已提交
3158
static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3159
{
3160
	struct pktgen_dev *pkt_dev, *best = NULL;
L
Luiz Capitulino 已提交
3161

L
Linus Torvalds 已提交
3162 3163
	if_lock(t);

3164 3165
	list_for_each_entry(pkt_dev, &t->if_list, list) {
		if (!pkt_dev->running)
L
Luiz Capitulino 已提交
3166 3167
			continue;
		if (best == NULL)
3168 3169 3170
			best = pkt_dev;
		else if (pkt_dev->next_tx_us < best->next_tx_us)
			best = pkt_dev;
L
Linus Torvalds 已提交
3171 3172
	}
	if_unlock(t);
L
Luiz Capitulino 已提交
3173
	return best;
L
Linus Torvalds 已提交
3174 3175
}

L
Luiz Capitulino 已提交
3176 3177
static void pktgen_stop(struct pktgen_thread *t)
{
3178
	struct pktgen_dev *pkt_dev;
L
Linus Torvalds 已提交
3179

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

L
Luiz Capitulino 已提交
3182
	if_lock(t);
L
Linus Torvalds 已提交
3183

3184 3185 3186 3187
	list_for_each_entry(pkt_dev, &t->if_list, list) {
		pktgen_stop_device(pkt_dev);
		if (pkt_dev->skb)
			kfree_skb(pkt_dev->skb);
3188

3189
		pkt_dev->skb = NULL;
3190
	}
L
Linus Torvalds 已提交
3191

L
Luiz Capitulino 已提交
3192
	if_unlock(t);
L
Linus Torvalds 已提交
3193 3194
}

3195 3196 3197 3198 3199 3200
/*
 * one of our devices needs to be removed - find it
 * and remove it
 */
static void pktgen_rem_one_if(struct pktgen_thread *t)
{
3201 3202
	struct list_head *q, *n;
	struct pktgen_dev *cur;
3203

S
Stephen Hemminger 已提交
3204
	pr_debug("pktgen: entering pktgen_rem_one_if\n");
3205 3206 3207

	if_lock(t);

3208 3209
	list_for_each_safe(q, n, &t->if_list) {
		cur = list_entry(q, struct pktgen_dev, list);
3210

L
Luiz Capitulino 已提交
3211 3212
		if (!cur->removal_mark)
			continue;
3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225

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

		pktgen_remove_device(t, cur);

		break;
	}

	if_unlock(t);
}

L
Luiz Capitulino 已提交
3226
static void pktgen_rem_all_ifs(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3227
{
3228 3229
	struct list_head *q, *n;
	struct pktgen_dev *cur;
L
Luiz Capitulino 已提交
3230 3231

	/* Remove all devices, free mem */
3232

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

3236 3237
	list_for_each_safe(q, n, &t->if_list) {
		cur = list_entry(q, struct pktgen_dev, list);
3238 3239 3240 3241 3242

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

L
Linus Torvalds 已提交
3243 3244 3245
		pktgen_remove_device(t, cur);
	}

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

L
Luiz Capitulino 已提交
3249
static void pktgen_rem_thread(struct pktgen_thread *t)
L
Linus Torvalds 已提交
3250
{
L
Luiz Capitulino 已提交
3251
	/* Remove from the thread list */
L
Linus Torvalds 已提交
3252

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

3255
	mutex_lock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3256

3257 3258
	list_del(&t->th_list);

3259
	mutex_unlock(&pktgen_thread_lock);
L
Linus Torvalds 已提交
3260 3261 3262 3263 3264 3265 3266 3267 3268
}

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 已提交
3269

L
Linus Torvalds 已提交
3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285
	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 已提交
3286

3287
	if ((netif_queue_stopped(odev) ||
R
Robert Olsson 已提交
3288
	     (pkt_dev->skb &&
3289
	      netif_subqueue_stopped(odev, pkt_dev->skb))) ||
R
Robert Olsson 已提交
3290
	    need_resched()) {
L
Linus Torvalds 已提交
3291
		idle_start = getCurUs();
L
Luiz Capitulino 已提交
3292

L
Linus Torvalds 已提交
3293 3294
		if (!netif_running(odev)) {
			pktgen_stop_device(pkt_dev);
3295 3296 3297
			if (pkt_dev->skb)
				kfree_skb(pkt_dev->skb);
			pkt_dev->skb = NULL;
L
Linus Torvalds 已提交
3298 3299
			goto out;
		}
L
Luiz Capitulino 已提交
3300
		if (need_resched())
L
Linus Torvalds 已提交
3301
			schedule();
L
Luiz Capitulino 已提交
3302

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

3305
		if (netif_queue_stopped(odev) ||
3306
		    netif_subqueue_stopped(odev, pkt_dev->skb)) {
L
Luiz Capitulino 已提交
3307
			pkt_dev->next_tx_us = getCurUs();	/* TODO */
L
Linus Torvalds 已提交
3308
			pkt_dev->next_tx_ns = 0;
L
Luiz Capitulino 已提交
3309
			goto out;	/* Try the next interface */
L
Linus Torvalds 已提交
3310 3311
		}
	}
L
Luiz Capitulino 已提交
3312

L
Linus Torvalds 已提交
3313
	if (pkt_dev->last_ok || !pkt_dev->skb) {
L
Luiz Capitulino 已提交
3314 3315
		if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
		    || (!pkt_dev->skb)) {
L
Linus Torvalds 已提交
3316
			/* build a new pkt */
L
Luiz Capitulino 已提交
3317
			if (pkt_dev->skb)
L
Linus Torvalds 已提交
3318
				kfree_skb(pkt_dev->skb);
L
Luiz Capitulino 已提交
3319

L
Linus Torvalds 已提交
3320 3321
			pkt_dev->skb = fill_packet(odev, pkt_dev);
			if (pkt_dev->skb == NULL) {
3322 3323
				printk(KERN_ERR "pktgen: ERROR: couldn't "
				       "allocate skb in fill_packet.\n");
L
Linus Torvalds 已提交
3324
				schedule();
L
Luiz Capitulino 已提交
3325
				pkt_dev->clone_count--;	/* back out increment, OOM */
L
Linus Torvalds 已提交
3326 3327 3328
				goto out;
			}
			pkt_dev->allocated_skbs++;
L
Luiz Capitulino 已提交
3329
			pkt_dev->clone_count = 0;	/* reset counter */
L
Linus Torvalds 已提交
3330 3331
		}
	}
3332

H
Herbert Xu 已提交
3333
	netif_tx_lock_bh(odev);
3334
	if (!netif_queue_stopped(odev) &&
3335
	    !netif_subqueue_stopped(odev, pkt_dev->skb)) {
L
Linus Torvalds 已提交
3336 3337

		atomic_inc(&(pkt_dev->skb->users));
L
Luiz Capitulino 已提交
3338
	      retry_now:
L
Linus Torvalds 已提交
3339 3340
		ret = odev->hard_start_xmit(pkt_dev->skb, odev);
		if (likely(ret == NETDEV_TX_OK)) {
L
Luiz Capitulino 已提交
3341
			pkt_dev->last_ok = 1;
L
Linus Torvalds 已提交
3342 3343 3344
			pkt_dev->sofar++;
			pkt_dev->seq_num++;
			pkt_dev->tx_bytes += pkt_dev->cur_pkt_size;
L
Luiz Capitulino 已提交
3345 3346

		} else if (ret == NETDEV_TX_LOCKED
L
Linus Torvalds 已提交
3347 3348 3349
			   && (odev->features & NETIF_F_LLTX)) {
			cpu_relax();
			goto retry_now;
L
Luiz Capitulino 已提交
3350 3351
		} else {	/* Retry it next time */

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

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

L
Linus Torvalds 已提交
3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
			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 已提交
3371
	}
L
Linus Torvalds 已提交
3372

L
Luiz Capitulino 已提交
3373 3374 3375
	else {			/* Retry it next time */
		pkt_dev->last_ok = 0;
		pkt_dev->next_tx_us = getCurUs();	/* TODO */
L
Linus Torvalds 已提交
3376
		pkt_dev->next_tx_ns = 0;
L
Luiz Capitulino 已提交
3377
	}
L
Linus Torvalds 已提交
3378

H
Herbert Xu 已提交
3379
	netif_tx_unlock_bh(odev);
L
Luiz Capitulino 已提交
3380

L
Linus Torvalds 已提交
3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392
	/* 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 已提交
3393

L
Linus Torvalds 已提交
3394 3395
		/* Done with this */
		pktgen_stop_device(pkt_dev);
3396 3397 3398
		if (pkt_dev->skb)
			kfree_skb(pkt_dev->skb);
		pkt_dev->skb = NULL;
L
Luiz Capitulino 已提交
3399 3400 3401
	}
out:;
}
L
Linus Torvalds 已提交
3402

3403
/*
L
Linus Torvalds 已提交
3404 3405 3406
 * Main loop of the thread goes here
 */

3407
static int pktgen_thread_worker(void *arg)
L
Linus Torvalds 已提交
3408 3409
{
	DEFINE_WAIT(wait);
3410
	struct pktgen_thread *t = arg;
L
Luiz Capitulino 已提交
3411
	struct pktgen_dev *pkt_dev = NULL;
L
Linus Torvalds 已提交
3412 3413
	int cpu = t->cpu;

3414
	BUG_ON(smp_processor_id() != cpu);
L
Linus Torvalds 已提交
3415 3416 3417

	init_waitqueue_head(&t->queue);

3418
	pr_debug("pktgen: starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
L
Linus Torvalds 已提交
3419

3420
	set_current_state(TASK_INTERRUPTIBLE);
L
Luiz Capitulino 已提交
3421

3422 3423
	set_freezable();

3424 3425
	while (!kthread_should_stop()) {
		pkt_dev = next_to_run(t);
L
Linus Torvalds 已提交
3426

3427 3428 3429 3430 3431 3432 3433 3434
		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 已提交
3435

3436
		__set_current_state(TASK_RUNNING);
L
Luiz Capitulino 已提交
3437

3438
		if (pkt_dev)
L
Linus Torvalds 已提交
3439 3440
			pktgen_xmit(pkt_dev);

L
Luiz Capitulino 已提交
3441
		if (t->control & T_STOP) {
L
Linus Torvalds 已提交
3442 3443 3444 3445
			pktgen_stop(t);
			t->control &= ~(T_STOP);
		}

L
Luiz Capitulino 已提交
3446
		if (t->control & T_RUN) {
L
Linus Torvalds 已提交
3447 3448 3449 3450
			pktgen_run(t);
			t->control &= ~(T_RUN);
		}

L
Luiz Capitulino 已提交
3451
		if (t->control & T_REMDEVALL) {
L
Linus Torvalds 已提交
3452
			pktgen_rem_all_ifs(t);
3453 3454 3455
			t->control &= ~(T_REMDEVALL);
		}

L
Luiz Capitulino 已提交
3456
		if (t->control & T_REMDEV) {
3457
			pktgen_rem_one_if(t);
L
Linus Torvalds 已提交
3458 3459 3460
			t->control &= ~(T_REMDEV);
		}

A
Andrew Morton 已提交
3461 3462
		try_to_freeze();

3463
		set_current_state(TASK_INTERRUPTIBLE);
L
Luiz Capitulino 已提交
3464
	}
L
Linus Torvalds 已提交
3465

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

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

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

3475
	return 0;
L
Linus Torvalds 已提交
3476 3477
}

L
Luiz Capitulino 已提交
3478 3479
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
					  const char *ifname)
L
Linus Torvalds 已提交
3480
{
3481
	struct pktgen_dev *p, *pkt_dev = NULL;
L
Luiz Capitulino 已提交
3482 3483
	if_lock(t);

3484
	list_for_each_entry(p, &t->if_list, list)
3485
		if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) {
3486
			pkt_dev = p;
L
Luiz Capitulino 已提交
3487 3488 3489 3490
			break;
		}

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

3495 3496
/*
 * Adds a dev at front of if_list.
L
Linus Torvalds 已提交
3497 3498
 */

L
Luiz Capitulino 已提交
3499 3500
static int add_dev_to_thread(struct pktgen_thread *t,
			     struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3501 3502
{
	int rv = 0;
L
Luiz Capitulino 已提交
3503 3504 3505 3506

	if_lock(t);

	if (pkt_dev->pg_thread) {
3507 3508
		printk(KERN_ERR "pktgen: ERROR: already assigned "
		       "to a thread.\n");
L
Luiz Capitulino 已提交
3509 3510 3511
		rv = -EBUSY;
		goto out;
	}
3512 3513

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

L
Luiz Capitulino 已提交
3517 3518 3519
out:
	if_unlock(t);
	return rv;
L
Linus Torvalds 已提交
3520 3521 3522 3523
}

/* Called under thread lock */

L
Luiz Capitulino 已提交
3524
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
L
Linus Torvalds 已提交
3525
{
L
Luiz Capitulino 已提交
3526
	struct pktgen_dev *pkt_dev;
3527
	int err;
L
Luiz Capitulino 已提交
3528

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

3531 3532
	pkt_dev = __pktgen_NN_threads(ifname, FIND);
	if (pkt_dev) {
3533
		printk(KERN_ERR "pktgen: ERROR: interface already used.\n");
L
Luiz Capitulino 已提交
3534 3535
		return -EBUSY;
	}
3536 3537 3538 3539 3540

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

L
Luiz Capitulino 已提交
3541
	pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state));
3542 3543 3544 3545
	if (pkt_dev->flows == NULL) {
		kfree(pkt_dev);
		return -ENOMEM;
	}
L
Luiz Capitulino 已提交
3546
	memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state));
3547

3548
	pkt_dev->removal_mark = 0;
3549 3550 3551 3552 3553 3554 3555 3556
	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 已提交
3557
	pkt_dev->udp_src_min = 9;	/* sink port */
3558 3559 3560 3561
	pkt_dev->udp_src_max = 9;
	pkt_dev->udp_dst_min = 9;
	pkt_dev->udp_dst_max = 9;

F
Francesco Fondelli 已提交
3562 3563 3564 3565 3566 3567 3568
	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;

3569 3570 3571
	err = pktgen_setup_dev(pkt_dev, ifname);
	if (err)
		goto out1;
3572

3573 3574
	pkt_dev->entry = proc_create(ifname, 0600,
				     pg_proc_dir, &pktgen_if_fops);
3575
	if (!pkt_dev->entry) {
3576
		printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
3577
		       PG_PROC_DIR, ifname);
3578 3579
		err = -EINVAL;
		goto out2;
3580
	}
3581
	pkt_dev->entry->data = pkt_dev;
J
Jamal Hadi Salim 已提交
3582 3583 3584 3585
#ifdef CONFIG_XFRM
	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
	pkt_dev->ipsproto = IPPROTO_ESP;
#endif
3586 3587

	return add_dev_to_thread(t, pkt_dev);
3588 3589 3590
out2:
	dev_put(pkt_dev->odev);
out1:
J
Jamal Hadi Salim 已提交
3591 3592 3593
#ifdef CONFIG_XFRM
	free_SAs(pkt_dev);
#endif
3594 3595 3596 3597
	if (pkt_dev->flows)
		vfree(pkt_dev->flows);
	kfree(pkt_dev);
	return err;
L
Linus Torvalds 已提交
3598 3599
}

3600
static int __init pktgen_create_thread(int cpu)
L
Linus Torvalds 已提交
3601
{
3602
	struct pktgen_thread *t;
3603
	struct proc_dir_entry *pe;
3604
	struct task_struct *p;
L
Luiz Capitulino 已提交
3605 3606 3607

	t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
	if (!t) {
3608 3609
		printk(KERN_ERR "pktgen: ERROR: out of memory, can't "
		       "create new thread.\n");
L
Luiz Capitulino 已提交
3610 3611 3612 3613
		return -ENOMEM;
	}

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

3616 3617 3618 3619 3620 3621
	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)) {
3622 3623
		printk(KERN_ERR "pktgen: kernel_thread() failed "
		       "for cpu %d\n", t->cpu);
3624 3625 3626 3627 3628 3629 3630
		list_del(&t->th_list);
		kfree(t);
		return PTR_ERR(p);
	}
	kthread_bind(p, cpu);
	t->tsk = p;

3631
	pe = proc_create(t->tsk->comm, 0600, pg_proc_dir, &pktgen_thread_fops);
L
Luiz Capitulino 已提交
3632
	if (!pe) {
3633
		printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
3634 3635 3636
		       PG_PROC_DIR, t->tsk->comm);
		kthread_stop(p);
		list_del(&t->th_list);
L
Luiz Capitulino 已提交
3637 3638 3639
		kfree(t);
		return -EINVAL;
	}
3640 3641

	pe->data = t;
L
Linus Torvalds 已提交
3642

3643
	wake_up_process(p);
L
Linus Torvalds 已提交
3644 3645 3646 3647

	return 0;
}

3648 3649
/*
 * Removes a device from the thread if_list.
L
Linus Torvalds 已提交
3650
 */
L
Luiz Capitulino 已提交
3651 3652
static void _rem_dev_from_if_list(struct pktgen_thread *t,
				  struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3653
{
3654 3655
	struct list_head *q, *n;
	struct pktgen_dev *p;
L
Linus Torvalds 已提交
3656

3657 3658 3659 3660
	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 已提交
3661 3662 3663
	}
}

L
Luiz Capitulino 已提交
3664 3665
static int pktgen_remove_device(struct pktgen_thread *t,
				struct pktgen_dev *pkt_dev)
L
Linus Torvalds 已提交
3666 3667
{

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

L
Luiz Capitulino 已提交
3670
	if (pkt_dev->running) {
3671 3672
		printk(KERN_WARNING "pktgen: WARNING: trying to remove a "
		       "running interface, stopping it now.\n");
L
Luiz Capitulino 已提交
3673 3674 3675 3676
		pktgen_stop_device(pkt_dev);
	}

	/* Dis-associate from the interface */
L
Linus Torvalds 已提交
3677 3678 3679

	if (pkt_dev->odev) {
		dev_put(pkt_dev->odev);
L
Luiz Capitulino 已提交
3680 3681 3682
		pkt_dev->odev = NULL;
	}

L
Linus Torvalds 已提交
3683 3684 3685 3686
	/* And update the thread if_list */

	_rem_dev_from_if_list(t, pkt_dev);

3687 3688
	if (pkt_dev->entry)
		remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
L
Linus Torvalds 已提交
3689

J
Jamal Hadi Salim 已提交
3690 3691 3692
#ifdef CONFIG_XFRM
	free_SAs(pkt_dev);
#endif
L
Linus Torvalds 已提交
3693 3694 3695
	if (pkt_dev->flows)
		vfree(pkt_dev->flows);
	kfree(pkt_dev);
L
Luiz Capitulino 已提交
3696
	return 0;
L
Linus Torvalds 已提交
3697 3698
}

L
Luiz Capitulino 已提交
3699
static int __init pg_init(void)
L
Linus Torvalds 已提交
3700 3701
{
	int cpu;
3702
	struct proc_dir_entry *pe;
L
Linus Torvalds 已提交
3703

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

3706
	pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
3707 3708 3709
	if (!pg_proc_dir)
		return -ENODEV;
	pg_proc_dir->owner = THIS_MODULE;
L
Linus Torvalds 已提交
3710

3711
	pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
L
Luiz Capitulino 已提交
3712
	if (pe == NULL) {
3713 3714
		printk(KERN_ERR "pktgen: ERROR: cannot create %s "
		       "procfs entry.\n", PGCTRL);
3715
		proc_net_remove(&init_net, PG_PROC_DIR);
L
Luiz Capitulino 已提交
3716 3717
		return -EINVAL;
	}
L
Linus Torvalds 已提交
3718

L
Luiz Capitulino 已提交
3719
	pe->data = NULL;
L
Linus Torvalds 已提交
3720 3721 3722

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

J
John Hawkes 已提交
3724
	for_each_online_cpu(cpu) {
3725
		int err;
L
Linus Torvalds 已提交
3726

3727
		err = pktgen_create_thread(cpu);
3728
		if (err)
3729 3730
			printk(KERN_WARNING "pktgen: WARNING: Cannot create "
			       "thread for cpu %d (%d)\n", cpu, err);
L
Luiz Capitulino 已提交
3731
	}
3732 3733

	if (list_empty(&pktgen_threads)) {
3734 3735
		printk(KERN_ERR "pktgen: ERROR: Initialization failed for "
		       "all threads\n");
3736 3737
		unregister_netdevice_notifier(&pktgen_notifier_block);
		remove_proc_entry(PGCTRL, pg_proc_dir);
3738
		proc_net_remove(&init_net, PG_PROC_DIR);
3739 3740 3741
		return -ENODEV;
	}

L
Luiz Capitulino 已提交
3742
	return 0;
L
Linus Torvalds 已提交
3743 3744 3745 3746
}

static void __exit pg_cleanup(void)
{
3747 3748
	struct pktgen_thread *t;
	struct list_head *q, *n;
L
Linus Torvalds 已提交
3749 3750 3751
	wait_queue_head_t queue;
	init_waitqueue_head(&queue);

L
Luiz Capitulino 已提交
3752
	/* Stop all interfaces & threads */
L
Linus Torvalds 已提交
3753

3754 3755
	list_for_each_safe(q, n, &pktgen_threads) {
		t = list_entry(q, struct pktgen_thread, th_list);
3756 3757
		kthread_stop(t->tsk);
		kfree(t);
L
Luiz Capitulino 已提交
3758
	}
L
Linus Torvalds 已提交
3759

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

L
Luiz Capitulino 已提交
3763
	/* Clean up proc file system */
3764
	remove_proc_entry(PGCTRL, pg_proc_dir);
3765
	proc_net_remove(&init_net, PG_PROC_DIR);
L
Linus Torvalds 已提交
3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
}

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);