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

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
187
/* Device flag bits */
Luiz Capitulino's avatar
Luiz Capitulino committed
188
189
190
191
192
193
194
195
#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 */
196
#define F_MPLS_RND    (1<<8)	/* Random MPLS labels */
Francesco Fondelli's avatar
Francesco Fondelli committed
197
198
#define F_VID_RND     (1<<9)	/* Random VLAN ID */
#define F_SVID_RND    (1<<10)	/* Random SVLAN ID */
199
#define F_FLOW_SEQ    (1<<11)	/* Sequential flows */
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
200
#define F_IPSEC_ON    (1<<12)	/* ipsec on for flows */
Robert Olsson's avatar
Robert Olsson committed
201
#define F_QUEUE_MAP_RND (1<<13)	/* queue map Random */
Robert Olsson's avatar
Robert Olsson committed
202
#define F_QUEUE_MAP_CPU (1<<14)	/* queue map mirrors smp_processor_id() */
Robert Olsson's avatar
Robert Olsson committed
203
#define F_NODE          (1<<15)	/* Node memory alloc*/
204
#define F_UDPCSUM       (1<<16)	/* Include UDP checksum */
205
#define F_NO_TIMESTAMP  (1<<17)	/* Don't timestamp packets (default TS) */
Linus Torvalds's avatar
Linus Torvalds committed
206
207

/* Thread control flag bits */
208
209
210
211
#define T_STOP        (1<<0)	/* Stop run */
#define T_RUN         (1<<1)	/* Start run */
#define T_REMDEVALL   (1<<2)	/* Remove all devs */
#define T_REMDEV      (1<<3)	/* Remove one dev */
Linus Torvalds's avatar
Linus Torvalds committed
212

213
214
215
216
/* Xmit modes */
#define M_START_XMIT		0	/* Default normal TX */
#define M_NETIF_RECEIVE 	1	/* Inject packets into stack */

217
/* If lock -- protects updating of if_list */
Linus Torvalds's avatar
Linus Torvalds committed
218
219
220
221
222
#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
223
224
#define PG_PROC_DIR "pktgen"
#define PGCTRL	    "pgctrl"
Linus Torvalds's avatar
Linus Torvalds committed
225
226
227

#define MAX_CFLOWS  65536

Francesco Fondelli's avatar
Francesco Fondelli committed
228
229
230
#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)

Luiz Capitulino's avatar
Luiz Capitulino committed
231
struct flow_state {
Al Viro's avatar
Al Viro committed
232
	__be32 cur_daddr;
Luiz Capitulino's avatar
Luiz Capitulino committed
233
	int count;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
234
235
236
#ifdef CONFIG_XFRM
	struct xfrm_state *x;
#endif
237
	__u32 flags;
Linus Torvalds's avatar
Linus Torvalds committed
238
239
};

240
241
242
/* flow flag bits */
#define F_INIT   (1<<0)		/* flow has been initialized */

Linus Torvalds's avatar
Linus Torvalds committed
243
244
245
246
struct pktgen_dev {
	/*
	 * Try to keep frequent/infrequent used vars. separated.
	 */
247
248
	struct proc_dir_entry *entry;	/* proc file */
	struct pktgen_thread *pg_thread;/* the owner */
249
	struct list_head list;		/* chaining in the thread's run-queue */
250
	struct rcu_head	 rcu;		/* freed by RCU */
Linus Torvalds's avatar
Linus Torvalds committed
251

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

Luiz Capitulino's avatar
Luiz Capitulino committed
254
255
256
257
	/* If min != max, then we will either do a linear iteration, or
	 * we will do a random selection from within the range.
	 */
	__u32 flags;
258
	int xmit_mode;
259
260
	int min_pkt_size;
	int max_pkt_size;
261
	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
Luiz Capitulino's avatar
Luiz Capitulino committed
262
	int nfrags;
263
264
265
	int removal_mark;	/* non-zero => the device is marked for
				 * removal by worker thread */

Eric Dumazet's avatar
Eric Dumazet committed
266
	struct page *page;
267
268
	u64 delay;		/* nano-seconds */

Luiz Capitulino's avatar
Luiz Capitulino committed
269
270
271
	__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 */
272
	__u64 errors;		/* Errors when trying to transmit, */
Luiz Capitulino's avatar
Luiz Capitulino committed
273
274
275
276
277
278

	/* runtime counters relating to clone_skb */

	__u64 allocated_skbs;
	__u32 clone_count;
	int last_ok;		/* Was last skb sent?
279
280
				 * Or a failed transmit of some sort?
				 * This will keep sequence numbers in order
Luiz Capitulino's avatar
Luiz Capitulino committed
281
				 */
282
283
284
285
286
	ktime_t next_tx;
	ktime_t started_at;
	ktime_t stopped_at;
	u64	idle_acc;	/* nano-seconds */

Luiz Capitulino's avatar
Luiz Capitulino committed
287
288
	__u32 seq_num;

289
290
291
292
293
294
295
296
	int clone_skb;		/*
				 * Use multiple SKBs during packet gen.
				 * If this number is greater than 1, then
				 * that many copies of the same packet will be
				 * sent before a new packet is allocated.
				 * If you want to send 1024 identical packets
				 * before creating a new packet,
				 * set clone_skb to 1024.
Luiz Capitulino's avatar
Luiz Capitulino committed
297
298
299
300
301
302
303
304
305
306
307
				 */

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

	struct in6_addr in6_saddr;
	struct in6_addr in6_daddr;
	struct in6_addr cur_in6_daddr;
	struct in6_addr cur_in6_saddr;
Linus Torvalds's avatar
Linus Torvalds committed
308
	/* For ranges */
Luiz Capitulino's avatar
Luiz Capitulino committed
309
310
311
312
313
314
315
316
	struct in6_addr min_in6_daddr;
	struct in6_addr max_in6_daddr;
	struct in6_addr min_in6_saddr;
	struct in6_addr max_in6_saddr;

	/* If we're doing ranges, random or incremental, then this
	 * defines the min/max for those ranges.
	 */
Al Viro's avatar
Al Viro committed
317
318
319
320
	__be32 saddr_min;	/* inclusive, source IP address */
	__be32 saddr_max;	/* exclusive, source IP address */
	__be32 daddr_min;	/* inclusive, dest IP address */
	__be32 daddr_max;	/* exclusive, dest IP address */
Luiz Capitulino's avatar
Luiz Capitulino committed
321
322
323
324
325
326

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

Francesco Fondelli's avatar
Francesco Fondelli committed
327
	/* DSCP + ECN */
328
329
330
331
	__u8 tos;            /* six MSB of (former) IPv4 TOS
				are for dscp codepoint */
	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6
				(see RFC 3260, sec. 4) */
Francesco Fondelli's avatar
Francesco Fondelli committed
332

333
	/* MPLS */
334
	unsigned int nr_labels;	/* Depth of stack, 0 = no MPLS */
335
336
	__be32 labels[MAX_MPLS_LABELS];

Francesco Fondelli's avatar
Francesco Fondelli committed
337
338
339
340
341
342
343
344
345
	/* VLAN/SVLAN (802.1Q/Q-in-Q) */
	__u8  vlan_p;
	__u8  vlan_cfi;
	__u16 vlan_id;  /* 0xffff means no vlan tag */

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

Luiz Capitulino's avatar
Luiz Capitulino committed
346
347
348
349
350
351
352
353
	__u32 src_mac_count;	/* How many MACs to iterate through */
	__u32 dst_mac_count;	/* How many MACs to iterate through */

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

	__u32 cur_dst_mac_offset;
	__u32 cur_src_mac_offset;
Al Viro's avatar
Al Viro committed
354
355
	__be32 cur_saddr;
	__be32 cur_daddr;
Eric Dumazet's avatar
Eric Dumazet committed
356
	__u16 ip_id;
Luiz Capitulino's avatar
Luiz Capitulino committed
357
358
	__u16 cur_udp_dst;
	__u16 cur_udp_src;
Robert Olsson's avatar
Robert Olsson committed
359
	__u16 cur_queue_map;
Luiz Capitulino's avatar
Luiz Capitulino committed
360
	__u32 cur_pkt_size;
361
	__u32 last_pkt_size;
Luiz Capitulino's avatar
Luiz Capitulino committed
362
363
364
365
366
367
368
369
370
371
372
373

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

374
	struct sk_buff *skb;	/* skb we are to transmit next, used for when we
Luiz Capitulino's avatar
Luiz Capitulino committed
375
376
				 * are transmitting the same one multiple times
				 */
377
378
379
380
381
382
383
384
	struct net_device *odev; /* The out-going device.
				  * Note that the device should have it's
				  * pg_info pointer pointing back to this
				  * device.
				  * Set when the user specifies the out-going
				  * device name (not when the inject is
				  * started as it used to do.)
				  */
385
	char odevname[32];
Linus Torvalds's avatar
Linus Torvalds committed
386
	struct flow_state *flows;
387
388
389
390
	unsigned int cflows;	/* Concurrent flows (config) */
	unsigned int lflow;		/* Flow length  (config) */
	unsigned int nflows;	/* accumulated flows (stats) */
	unsigned int curfl;		/* current sequenced flow (state)*/
Robert Olsson's avatar
Robert Olsson committed
391
392
393

	u16 queue_map_min;
	u16 queue_map_max;
394
	__u32 skb_priority;	/* skb priority field */
395
	unsigned int burst;	/* number of duplicated packets to burst */
Robert Olsson's avatar
Robert Olsson committed
396
	int node;               /* Memory node */
Robert Olsson's avatar
Robert Olsson committed
397

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
398
399
400
#ifdef CONFIG_XFRM
	__u8	ipsmode;		/* IPSEC mode (config) */
	__u8	ipsproto;		/* IPSEC type (config) */
401
	__u32	spi;
402
403
	struct dst_entry dst;
	struct dst_ops dstops;
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
404
#endif
405
	char result[512];
Linus Torvalds's avatar
Linus Torvalds committed
406
407
408
};

struct pktgen_hdr {
Al Viro's avatar
Al Viro committed
409
410
411
412
	__be32 pgh_magic;
	__be32 seq_num;
	__be32 tv_sec;
	__be32 tv_usec;
Linus Torvalds's avatar
Linus Torvalds committed
413
414
};

Cong Wang's avatar
Cong Wang committed
415
416
417
418
419
420
421
422
423

static int pg_net_id __read_mostly;

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

Linus Torvalds's avatar
Linus Torvalds committed
425
struct pktgen_thread {
426
	spinlock_t if_lock;		/* for list of devices */
427
	struct list_head if_list;	/* All device here */
428
	struct list_head th_list;
429
	struct task_struct *tsk;
Luiz Capitulino's avatar
Luiz Capitulino committed
430
431
	char result[512];

432
433
	/* Field for thread to receive "posted" events terminate,
	   stop ifs etc. */
Luiz Capitulino's avatar
Luiz Capitulino committed
434
435

	u32 control;
Linus Torvalds's avatar
Linus Torvalds committed
436
437
	int cpu;

Luiz Capitulino's avatar
Luiz Capitulino committed
438
	wait_queue_head_t queue;
439
	struct completion start_done;
Cong Wang's avatar
Cong Wang committed
440
	struct pktgen_net *net;
Linus Torvalds's avatar
Linus Torvalds committed
441
442
443
444
445
};

#define REMOVE 1
#define FIND   0

Stephen Hemminger's avatar
Stephen Hemminger committed
446
static const char version[] =
447
448
	"Packet Generator for packet performance testing. "
	"Version: " VERSION "\n";
Linus Torvalds's avatar
Linus Torvalds committed
449

Luiz Capitulino's avatar
Luiz Capitulino committed
450
451
452
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,
453
					  const char *ifname, bool exact);
Linus Torvalds's avatar
Linus Torvalds committed
454
static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
Cong Wang's avatar
Cong Wang committed
455
456
457
static void pktgen_run_all_threads(struct pktgen_net *pn);
static void pktgen_reset_all_threads(struct pktgen_net *pn);
static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn);
458

Luiz Capitulino's avatar
Luiz Capitulino committed
459
static void pktgen_stop(struct pktgen_thread *t);
Linus Torvalds's avatar
Linus Torvalds committed
460
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
461

Linus Torvalds's avatar
Linus Torvalds committed
462
/* Module parameters, defaults. */
463
464
465
466
static int pg_count_d __read_mostly = 1000;
static int pg_delay_d __read_mostly;
static int pg_clone_skb_d  __read_mostly;
static int debug  __read_mostly;
Linus Torvalds's avatar
Linus Torvalds committed
467

468
static DEFINE_MUTEX(pktgen_thread_lock);
Linus Torvalds's avatar
Linus Torvalds committed
469
470
471
472
473
474

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

/*
475
 * /proc handling functions
Linus Torvalds's avatar
Linus Torvalds committed
476
477
478
 *
 */

479
static int pgctrl_show(struct seq_file *seq, void *v)
Luiz Capitulino's avatar
Luiz Capitulino committed
480
{
Stephen Hemminger's avatar
Stephen Hemminger committed
481
	seq_puts(seq, version);
482
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
483
484
}

485
486
static ssize_t pgctrl_write(struct file *file, const char __user *buf,
			    size_t count, loff_t *ppos)
Linus Torvalds's avatar
Linus Torvalds committed
487
{
488
	char data[128];
Cong Wang's avatar
Cong Wang committed
489
	struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
Linus Torvalds's avatar
Linus Torvalds committed
490

491
492
	if (!capable(CAP_NET_ADMIN))
		return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
493

494
495
496
	if (count == 0)
		return -EINVAL;

497
498
	if (count > sizeof(data))
		count = sizeof(data);
Linus Torvalds's avatar
Linus Torvalds committed
499

500
501
502
	if (copy_from_user(data, buf, count))
		return -EFAULT;

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

Luiz Capitulino's avatar
Luiz Capitulino committed
505
	if (!strcmp(data, "stop"))
Cong Wang's avatar
Cong Wang committed
506
		pktgen_stop_all_threads_ifs(pn);
Linus Torvalds's avatar
Linus Torvalds committed
507

Luiz Capitulino's avatar
Luiz Capitulino committed
508
	else if (!strcmp(data, "start"))
Cong Wang's avatar
Cong Wang committed
509
		pktgen_run_all_threads(pn);
Linus Torvalds's avatar
Linus Torvalds committed
510

511
	else if (!strcmp(data, "reset"))
Cong Wang's avatar
Cong Wang committed
512
		pktgen_reset_all_threads(pn);
513

Luiz Capitulino's avatar
Luiz Capitulino committed
514
	else
515
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
516

517
	return count;
Linus Torvalds's avatar
Linus Torvalds committed
518
519
}

520
521
static int pgctrl_open(struct inode *inode, struct file *file)
{
Al Viro's avatar
Al Viro committed
522
	return single_open(file, pgctrl_show, PDE_DATA(inode));
523
524
}

525
static const struct file_operations pktgen_fops = {
Luiz Capitulino's avatar
Luiz Capitulino committed
526
527
528
529
530
531
	.owner   = THIS_MODULE,
	.open    = pgctrl_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.write   = pgctrl_write,
	.release = single_release,
532
533
534
};

static int pktgen_if_show(struct seq_file *seq, void *v)
Linus Torvalds's avatar
Linus Torvalds committed
535
{
Stephen Hemminger's avatar
Stephen Hemminger committed
536
	const struct pktgen_dev *pkt_dev = seq->private;
537
538
	ktime_t stopped;
	u64 idle;
Luiz Capitulino's avatar
Luiz Capitulino committed
539
540
541
542
543
544
545

	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,
546
547
		   "     frags: %d  delay: %llu  clone_skb: %d  ifname: %s\n",
		   pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
548
		   pkt_dev->clone_skb, pkt_dev->odevname);
Luiz Capitulino's avatar
Luiz Capitulino committed
549
550
551
552

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

Robert Olsson's avatar
Robert Olsson committed
553
554
555
556
557
	seq_printf(seq,
		   "     queue_map_min: %u  queue_map_max: %u\n",
		   pkt_dev->queue_map_min,
		   pkt_dev->queue_map_max);

558
559
560
561
	if (pkt_dev->skb_priority)
		seq_printf(seq, "     skb_priority: %u\n",
			   pkt_dev->skb_priority);

Luiz Capitulino's avatar
Luiz Capitulino committed
562
563
	if (pkt_dev->flags & F_IPV6) {
		seq_printf(seq,
564
565
566
567
568
569
			   "     saddr: %pI6c  min_saddr: %pI6c  max_saddr: %pI6c\n"
			   "     daddr: %pI6c  min_daddr: %pI6c  max_daddr: %pI6c\n",
			   &pkt_dev->in6_saddr,
			   &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr,
			   &pkt_dev->in6_daddr,
			   &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr);
570
571
572
573
	} else {
		seq_printf(seq,
			   "     dst_min: %s  dst_max: %s\n",
			   pkt_dev->dst_min, pkt_dev->dst_max);
Luiz Capitulino's avatar
Luiz Capitulino committed
574
		seq_printf(seq,
575
			   "     src_min: %s  src_max: %s\n",
576
577
			   pkt_dev->src_min, pkt_dev->src_max);
	}
Linus Torvalds's avatar
Linus Torvalds committed
578

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

Johannes Berg's avatar
Johannes Berg committed
581
582
583
	seq_printf(seq, "%pM ",
		   is_zero_ether_addr(pkt_dev->src_mac) ?
			     pkt_dev->odev->dev_addr : pkt_dev->src_mac);
Luiz Capitulino's avatar
Luiz Capitulino committed
584

585
	seq_puts(seq, "dst_mac: ");
Johannes Berg's avatar
Johannes Berg committed
586
	seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
Luiz Capitulino's avatar
Luiz Capitulino committed
587
588

	seq_printf(seq,
589
590
		   "     udp_src_min: %d  udp_src_max: %d"
		   "  udp_dst_min: %d  udp_dst_max: %d\n",
Luiz Capitulino's avatar
Luiz Capitulino committed
591
592
593
594
		   pkt_dev->udp_src_min, pkt_dev->udp_src_max,
		   pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);

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

598
	if (pkt_dev->nr_labels) {
599
		unsigned int i;
600
		seq_puts(seq, "     mpls: ");
601
		for (i = 0; i < pkt_dev->nr_labels; i++)
602
603
604
605
			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
	}

606
	if (pkt_dev->vlan_id != 0xffff)
Francesco Fondelli's avatar
Francesco Fondelli committed
607
		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
608
609
			   pkt_dev->vlan_id, pkt_dev->vlan_p,
			   pkt_dev->vlan_cfi);
Francesco Fondelli's avatar
Francesco Fondelli committed
610

611
	if (pkt_dev->svlan_id != 0xffff)
Francesco Fondelli's avatar
Francesco Fondelli committed
612
		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
613
614
			   pkt_dev->svlan_id, pkt_dev->svlan_p,
			   pkt_dev->svlan_cfi);
Francesco Fondelli's avatar
Francesco Fondelli committed
615

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

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

622
623
624
	if (pkt_dev->burst > 1)
		seq_printf(seq, "     burst: %d\n", pkt_dev->burst);

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

628
629
630
	if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
		seq_puts(seq, "     xmit_mode: netif_receive\n");

631
	seq_puts(seq, "     Flags: ");
632

Luiz Capitulino's avatar
Luiz Capitulino committed
633
	if (pkt_dev->flags & F_IPV6)
634
		seq_puts(seq, "IPV6  ");
Linus Torvalds's avatar
Linus Torvalds committed
635

Luiz Capitulino's avatar
Luiz Capitulino committed
636
	if (pkt_dev->flags & F_IPSRC_RND)
637
		seq_puts(seq, "IPSRC_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
638

Luiz Capitulino's avatar
Luiz Capitulino committed
639
	if (pkt_dev->flags & F_IPDST_RND)
640
		seq_puts(seq, "IPDST_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
641

Luiz Capitulino's avatar
Luiz Capitulino committed
642
	if (pkt_dev->flags & F_TXSIZE_RND)
643
		seq_puts(seq, "TXSIZE_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
644

Luiz Capitulino's avatar
Luiz Capitulino committed
645
	if (pkt_dev->flags & F_UDPSRC_RND)
646
		seq_puts(seq, "UDPSRC_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
647

Luiz Capitulino's avatar
Luiz Capitulino committed
648
	if (pkt_dev->flags & F_UDPDST_RND)
649
		seq_puts(seq, "UDPDST_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
650

651
	if (pkt_dev->flags & F_UDPCSUM)
652
		seq_puts(seq, "UDPCSUM  ");
653

654
655
656
	if (pkt_dev->flags & F_NO_TIMESTAMP)
		seq_puts(seq, "NO_TIMESTAMP  ");

657
	if (pkt_dev->flags & F_MPLS_RND)
658
		seq_puts(seq,  "MPLS_RND  ");
659

Robert Olsson's avatar
Robert Olsson committed
660
	if (pkt_dev->flags & F_QUEUE_MAP_RND)
661
		seq_puts(seq,  "QUEUE_MAP_RND  ");
Robert Olsson's avatar
Robert Olsson committed
662

Robert Olsson's avatar
Robert Olsson committed
663
	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
664
		seq_puts(seq,  "QUEUE_MAP_CPU  ");
Robert Olsson's avatar
Robert Olsson committed
665

666
667
	if (pkt_dev->cflows) {
		if (pkt_dev->flags & F_FLOW_SEQ)
668
			seq_puts(seq,  "FLOW_SEQ  "); /*in sequence flows*/
669
		else
670
			seq_puts(seq,  "FLOW_RND  ");
671
672
	}

Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
673
#ifdef CONFIG_XFRM
674
	if (pkt_dev->flags & F_IPSEC_ON) {
675
		seq_puts(seq,  "IPSEC  ");
676
677
678
		if (pkt_dev->spi)
			seq_printf(seq, "spi:%u", pkt_dev->spi);
	}
Jamal Hadi Salim's avatar
Jamal Hadi Salim committed
679
680
#endif

Luiz Capitulino's avatar
Luiz Capitulino committed
681
	if (pkt_dev->flags & F_MACSRC_RND)
682
		seq_puts(seq, "MACSRC_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
683

Luiz Capitulino's avatar
Luiz Capitulino committed
684
	if (pkt_dev->flags & F_MACDST_RND)
685
		seq_puts(seq, "MACDST_RND  ");
Linus Torvalds's avatar
Linus Torvalds committed
686

Francesco Fondelli's avatar
Francesco Fondelli committed
687
	if (pkt_dev->flags & F_VID_RND)
688
		seq_puts(seq, "VID_RND  ");
Francesco Fondelli's avatar
Francesco Fondelli committed
689
690

	if (pkt_dev->flags & F_SVID_RND)
691
		seq_puts(seq, "SVID_RND  ");
Francesco Fondelli's avatar
Francesco Fondelli committed
692

Robert Olsson's avatar
Robert Olsson committed
693
	if (pkt_dev->flags & F_NODE)
694
		seq_puts(seq, "NODE_ALLOC  ");
Robert Olsson's avatar
Robert Olsson committed
695

Luiz Capitulino's avatar
Luiz Capitulino committed
696
697
	seq_puts(seq, "\n");

698
	/* not really stopped, more like last-running-at */
699
	stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at;
700
701
	idle = pkt_dev->idle_acc;
	do_div(idle, NSEC_PER_USEC);
Linus Torvalds's avatar
Linus Torvalds committed
702

Luiz Capitulino's avatar
Luiz Capitulino committed
703
	seq_printf(seq,
704
		   "Current:\n     pkts-sofar: %llu  errors: %llu\n",
Luiz Capitulino's avatar
Luiz Capitulino committed
705
		   (unsigned long long)pkt_dev->sofar,
706
707
708
709
710
711
712
		   (unsigned long long)pkt_dev->errors);

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

Luiz Capitulino's avatar
Luiz Capitulino committed
714
715
	seq_printf(seq,
		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
716
717
		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
		   pkt_dev->cur_src_mac_offset);
Linus Torvalds's avatar
Linus Torvalds committed
718

Luiz Capitulino's avatar
Luiz Capitulino committed
719
	if (pkt_dev->flags & F_IPV6) {
720
721
722
		seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
				&pkt_dev->cur_in6_saddr,
				&pkt_dev->cur_in6_daddr);
Luiz Capitulino's avatar
Luiz Capitulino committed
723
	} else
724
725
		seq_printf(seq, "     cur_saddr: %pI4  cur_daddr: %pI4\n",
			   &pkt_dev->cur_saddr, &pkt_dev->cur_daddr);
Linus Torvalds's avatar
Linus Torvalds committed
726

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

Robert Olsson's avatar
Robert Olsson committed
730
731
	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);

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

	if (pkt_dev->result[0])
Luiz Capitulino's avatar
Luiz Capitulino committed
735
		seq_printf(seq, "Result: %s\n", pkt_dev->result);
Linus Torvalds's avatar
Linus Torvalds committed
736
	else
737
		seq_puts(seq, "Result: Idle\n");
Linus Torvalds's avatar
Linus Torvalds committed
738

739
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
740
741
}

742

743
744
static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
		     __u32 *num)
745
746
747
748
{
	int i = 0;
	*num = 0;

749
	for (; i < maxlen; i++) {
750
		int value;
751
752
753
754
		char c;
		*num <<= 4;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
755
756
757
		value = hex_to_bin(c);
		if (value >= 0)
			*num |= value;
758
759
760
761
762
763
		else
			break;
	}
	return i;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
764
765
static int count_trail_chars(const char __user * user_buffer,
			     unsigned int maxlen)
Linus Torvalds's avatar
Linus Torvalds committed
766
767
768
769
{
	int i;

	for (i = 0; i < maxlen; i++) {
Luiz Capitulino's avatar
Luiz Capitulino committed
770
771
772
773
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
Linus Torvalds's avatar
Linus Torvalds committed
774
775
776
777
778
779
780
781
782
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
		case '=':
			break;
		default:
			goto done;
783
		}
Linus Torvalds's avatar
Linus Torvalds committed
784
785
786
787
788
	}
done:
	return i;
}

789
790
static long num_arg(const char __user *user_buffer, unsigned long maxlen,
				unsigned long *num)
Linus Torvalds's avatar
Linus Torvalds committed
791
{
792
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
793
	*num = 0;
Luiz Capitulino's avatar
Luiz Capitulino committed
794

795
	for (i = 0; i < maxlen; i++) {
Luiz Capitulino's avatar
Luiz Capitulino committed
796
797
798
799
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		if ((c >= '0') && (c <= '9')) {
Linus Torvalds's avatar
Linus Torvalds committed
800
			*num *= 10;
Luiz Capitulino's avatar
Luiz Capitulino committed
801
			*num += c - '0';
Linus Torvalds's avatar
Linus Torvalds committed
802
803
804
805
806
807
		} else
			break;
	}
	return i;
}

Luiz Capitulino's avatar
Luiz Capitulino committed
808
static int strn_len(const char __user * user_buffer, unsigned int maxlen)
Linus Torvalds's avatar
Linus Torvalds committed
809
{
810
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
811

812
	for (i = 0; i < maxlen; i++) {
Luiz Capitulino's avatar
Luiz Capitulino committed
813
814
815
816
		char c;
		if (get_user(c, &user_buffer[i]))
			return -EFAULT;
		switch (c) {
Linus Torvalds's avatar
Linus Torvalds committed
817
818
819
820
821
822
823
824
		case '\"':
		case '\n':
		case '\r':
		case '\t':
		case ' ':
			goto done_str;
		default:
			break;
825
		}
Linus Torvalds's avatar
Linus Torvalds committed
826
827
828
829
830
	}
done_str:
	return i;
}

831
832
static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
{
833
	unsigned int n = 0;
834
835
836
837
838
839
840
	char c;
	ssize_t i = 0;
	int len;

	pkt_dev->nr_labels = 0;
	do {
		__u32 tmp;
Francesco Fondelli's avatar
Francesco Fondelli committed
841
		len = hex32_arg(&buffer[i], 8, &tmp);
842
843
844
845
846
847
848
849
850
851
852
853
		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;
854
	} while (c == ',');
855
856
857
858
859

	pkt_dev->nr_labels = n;
	return i;
}

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

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
888
889
890
	/* Read variable name */

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
904
905
906
	i += len;

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

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

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

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

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

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

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed