1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Authors: 3*1da177e4SLinus Torvalds * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> 4*1da177e4SLinus Torvalds * Uppsala University and 5*1da177e4SLinus Torvalds * Swedish University of Agricultural Sciences 6*1da177e4SLinus Torvalds * 7*1da177e4SLinus Torvalds * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 8*1da177e4SLinus Torvalds * Ben Greear <greearb@candelatech.com> 9*1da177e4SLinus Torvalds * Jens L��s <jens.laas@data.slu.se> 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 12*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 13*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 14*1da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 15*1da177e4SLinus Torvalds * 16*1da177e4SLinus Torvalds * 17*1da177e4SLinus Torvalds * A tool for loading the network with preconfigurated packets. 18*1da177e4SLinus Torvalds * The tool is implemented as a linux module. Parameters are output 19*1da177e4SLinus Torvalds * device, delay (to hard_xmit), number of packets, and whether 20*1da177e4SLinus Torvalds * to use multiple SKBs or just the same one. 21*1da177e4SLinus Torvalds * pktgen uses the installed interface's output routine. 22*1da177e4SLinus Torvalds * 23*1da177e4SLinus Torvalds * Additional hacking by: 24*1da177e4SLinus Torvalds * 25*1da177e4SLinus Torvalds * Jens.Laas@data.slu.se 26*1da177e4SLinus Torvalds * Improved by ANK. 010120. 27*1da177e4SLinus Torvalds * Improved by ANK even more. 010212. 28*1da177e4SLinus Torvalds * MAC address typo fixed. 010417 --ro 29*1da177e4SLinus Torvalds * Integrated. 020301 --DaveM 30*1da177e4SLinus Torvalds * Added multiskb option 020301 --DaveM 31*1da177e4SLinus Torvalds * Scaling of results. 020417--sigurdur@linpro.no 32*1da177e4SLinus Torvalds * Significant re-work of the module: 33*1da177e4SLinus Torvalds * * Convert to threaded model to more efficiently be able to transmit 34*1da177e4SLinus Torvalds * and receive on multiple interfaces at once. 35*1da177e4SLinus Torvalds * * Converted many counters to __u64 to allow longer runs. 36*1da177e4SLinus Torvalds * * Allow configuration of ranges, like min/max IP address, MACs, 37*1da177e4SLinus Torvalds * and UDP-ports, for both source and destination, and can 38*1da177e4SLinus Torvalds * set to use a random distribution or sequentially walk the range. 39*1da177e4SLinus Torvalds * * Can now change most values after starting. 40*1da177e4SLinus Torvalds * * Place 12-byte packet in UDP payload with magic number, 41*1da177e4SLinus Torvalds * sequence number, and timestamp. 42*1da177e4SLinus Torvalds * * Add receiver code that detects dropped pkts, re-ordered pkts, and 43*1da177e4SLinus Torvalds * latencies (with micro-second) precision. 44*1da177e4SLinus Torvalds * * Add IOCTL interface to easily get counters & configuration. 45*1da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 46*1da177e4SLinus Torvalds * 47*1da177e4SLinus Torvalds * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 48*1da177e4SLinus Torvalds * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 49*1da177e4SLinus Torvalds * as a "fastpath" with a configurable number of clones after alloc's. 50*1da177e4SLinus Torvalds * clone_skb=0 means all packets are allocated this also means ranges time 51*1da177e4SLinus Torvalds * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 52*1da177e4SLinus Torvalds * clones. 53*1da177e4SLinus Torvalds * 54*1da177e4SLinus Torvalds * Also moved to /proc/net/pktgen/ 55*1da177e4SLinus Torvalds * --ro 56*1da177e4SLinus Torvalds * 57*1da177e4SLinus Torvalds * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever 58*1da177e4SLinus Torvalds * mistakes. Also merged in DaveM's patch in the -pre6 patch. 59*1da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 60*1da177e4SLinus Torvalds * 61*1da177e4SLinus Torvalds * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) 62*1da177e4SLinus Torvalds * 63*1da177e4SLinus Torvalds * 64*1da177e4SLinus Torvalds * 021124 Finished major redesign and rewrite for new functionality. 65*1da177e4SLinus Torvalds * See Documentation/networking/pktgen.txt for how to use this. 66*1da177e4SLinus Torvalds * 67*1da177e4SLinus Torvalds * The new operation: 68*1da177e4SLinus Torvalds * For each CPU one thread/process is created at start. This process checks 69*1da177e4SLinus Torvalds * for running devices in the if_list and sends packets until count is 0 it 70*1da177e4SLinus Torvalds * also the thread checks the thread->control which is used for inter-process 71*1da177e4SLinus Torvalds * communication. controlling process "posts" operations to the threads this 72*1da177e4SLinus Torvalds * way. The if_lock should be possible to remove when add/rem_device is merged 73*1da177e4SLinus Torvalds * into this too. 74*1da177e4SLinus Torvalds * 75*1da177e4SLinus Torvalds * By design there should only be *one* "controlling" process. In practice 76*1da177e4SLinus Torvalds * multiple write accesses gives unpredictable result. Understood by "write" 77*1da177e4SLinus Torvalds * to /proc gives result code thats should be read be the "writer". 78*1da177e4SLinus Torvalds * For pratical use this should be no problem. 79*1da177e4SLinus Torvalds * 80*1da177e4SLinus Torvalds * Note when adding devices to a specific CPU there good idea to also assign 81*1da177e4SLinus Torvalds * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 82*1da177e4SLinus Torvalds * --ro 83*1da177e4SLinus Torvalds * 84*1da177e4SLinus Torvalds * Fix refcount off by one if first packet fails, potential null deref, 85*1da177e4SLinus Torvalds * memleak 030710- KJP 86*1da177e4SLinus Torvalds * 87*1da177e4SLinus Torvalds * First "ranges" functionality for ipv6 030726 --ro 88*1da177e4SLinus Torvalds * 89*1da177e4SLinus Torvalds * Included flow support. 030802 ANK. 90*1da177e4SLinus Torvalds * 91*1da177e4SLinus Torvalds * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> 92*1da177e4SLinus Torvalds * 93*1da177e4SLinus Torvalds * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 94*1da177e4SLinus Torvalds * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 95*1da177e4SLinus Torvalds * 96*1da177e4SLinus Torvalds * New xmit() return, do_div and misc clean up by Stephen Hemminger 97*1da177e4SLinus Torvalds * <shemminger@osdl.org> 040923 98*1da177e4SLinus Torvalds * 99*1da177e4SLinus Torvalds * Rany Dunlap fixed u64 printk compiler waring 100*1da177e4SLinus Torvalds * 101*1da177e4SLinus Torvalds * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> 102*1da177e4SLinus Torvalds * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 103*1da177e4SLinus Torvalds * 104*1da177e4SLinus Torvalds * Corrections from Nikolai Malykh (nmalykh@bilim.com) 105*1da177e4SLinus Torvalds * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 106*1da177e4SLinus Torvalds * 107*1da177e4SLinus Torvalds * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 108*1da177e4SLinus Torvalds * 050103 109*1da177e4SLinus Torvalds */ 110*1da177e4SLinus Torvalds #include <linux/sys.h> 111*1da177e4SLinus Torvalds #include <linux/types.h> 112*1da177e4SLinus Torvalds #include <linux/module.h> 113*1da177e4SLinus Torvalds #include <linux/moduleparam.h> 114*1da177e4SLinus Torvalds #include <linux/kernel.h> 115*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 116*1da177e4SLinus Torvalds #include <linux/sched.h> 117*1da177e4SLinus Torvalds #include <linux/slab.h> 118*1da177e4SLinus Torvalds #include <linux/vmalloc.h> 119*1da177e4SLinus Torvalds #include <linux/sched.h> 120*1da177e4SLinus Torvalds #include <linux/unistd.h> 121*1da177e4SLinus Torvalds #include <linux/string.h> 122*1da177e4SLinus Torvalds #include <linux/ptrace.h> 123*1da177e4SLinus Torvalds #include <linux/errno.h> 124*1da177e4SLinus Torvalds #include <linux/ioport.h> 125*1da177e4SLinus Torvalds #include <linux/interrupt.h> 126*1da177e4SLinus Torvalds #include <linux/delay.h> 127*1da177e4SLinus Torvalds #include <linux/timer.h> 128*1da177e4SLinus Torvalds #include <linux/init.h> 129*1da177e4SLinus Torvalds #include <linux/skbuff.h> 130*1da177e4SLinus Torvalds #include <linux/netdevice.h> 131*1da177e4SLinus Torvalds #include <linux/inet.h> 132*1da177e4SLinus Torvalds #include <linux/inetdevice.h> 133*1da177e4SLinus Torvalds #include <linux/rtnetlink.h> 134*1da177e4SLinus Torvalds #include <linux/if_arp.h> 135*1da177e4SLinus Torvalds #include <linux/in.h> 136*1da177e4SLinus Torvalds #include <linux/ip.h> 137*1da177e4SLinus Torvalds #include <linux/ipv6.h> 138*1da177e4SLinus Torvalds #include <linux/udp.h> 139*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 140*1da177e4SLinus Torvalds #include <linux/wait.h> 141*1da177e4SLinus Torvalds #include <net/checksum.h> 142*1da177e4SLinus Torvalds #include <net/ipv6.h> 143*1da177e4SLinus Torvalds #include <net/addrconf.h> 144*1da177e4SLinus Torvalds #include <asm/byteorder.h> 145*1da177e4SLinus Torvalds #include <linux/rcupdate.h> 146*1da177e4SLinus Torvalds #include <asm/bitops.h> 147*1da177e4SLinus Torvalds #include <asm/io.h> 148*1da177e4SLinus Torvalds #include <asm/dma.h> 149*1da177e4SLinus Torvalds #include <asm/uaccess.h> 150*1da177e4SLinus Torvalds #include <asm/div64.h> /* do_div */ 151*1da177e4SLinus Torvalds #include <asm/timex.h> 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds 154*1da177e4SLinus Torvalds #define VERSION "pktgen v2.61: Packet Generator for packet performance testing.\n" 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds /* #define PG_DEBUG(a) a */ 157*1da177e4SLinus Torvalds #define PG_DEBUG(a) 158*1da177e4SLinus Torvalds 159*1da177e4SLinus Torvalds /* The buckets are exponential in 'width' */ 160*1da177e4SLinus Torvalds #define LAT_BUCKETS_MAX 32 161*1da177e4SLinus Torvalds #define IP_NAME_SZ 32 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds /* Device flag bits */ 164*1da177e4SLinus Torvalds #define F_IPSRC_RND (1<<0) /* IP-Src Random */ 165*1da177e4SLinus Torvalds #define F_IPDST_RND (1<<1) /* IP-Dst Random */ 166*1da177e4SLinus Torvalds #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ 167*1da177e4SLinus Torvalds #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ 168*1da177e4SLinus Torvalds #define F_MACSRC_RND (1<<4) /* MAC-Src Random */ 169*1da177e4SLinus Torvalds #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ 170*1da177e4SLinus Torvalds #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ 171*1da177e4SLinus Torvalds #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds /* Thread control flag bits */ 174*1da177e4SLinus Torvalds #define T_TERMINATE (1<<0) 175*1da177e4SLinus Torvalds #define T_STOP (1<<1) /* Stop run */ 176*1da177e4SLinus Torvalds #define T_RUN (1<<2) /* Start run */ 177*1da177e4SLinus Torvalds #define T_REMDEV (1<<3) /* Remove all devs */ 178*1da177e4SLinus Torvalds 179*1da177e4SLinus Torvalds /* Locks */ 180*1da177e4SLinus Torvalds #define thread_lock() spin_lock(&_thread_lock) 181*1da177e4SLinus Torvalds #define thread_unlock() spin_unlock(&_thread_lock) 182*1da177e4SLinus Torvalds 183*1da177e4SLinus Torvalds /* If lock -- can be removed after some work */ 184*1da177e4SLinus Torvalds #define if_lock(t) spin_lock(&(t->if_lock)); 185*1da177e4SLinus Torvalds #define if_unlock(t) spin_unlock(&(t->if_lock)); 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 188*1da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 189*1da177e4SLinus Torvalds #define PG_PROC_DIR "pktgen" 190*1da177e4SLinus Torvalds 191*1da177e4SLinus Torvalds #define MAX_CFLOWS 65536 192*1da177e4SLinus Torvalds 193*1da177e4SLinus Torvalds struct flow_state 194*1da177e4SLinus Torvalds { 195*1da177e4SLinus Torvalds __u32 cur_daddr; 196*1da177e4SLinus Torvalds int count; 197*1da177e4SLinus Torvalds }; 198*1da177e4SLinus Torvalds 199*1da177e4SLinus Torvalds struct pktgen_dev { 200*1da177e4SLinus Torvalds 201*1da177e4SLinus Torvalds /* 202*1da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 203*1da177e4SLinus Torvalds */ 204*1da177e4SLinus Torvalds 205*1da177e4SLinus Torvalds char ifname[32]; 206*1da177e4SLinus Torvalds struct proc_dir_entry *proc_ent; 207*1da177e4SLinus Torvalds char result[512]; 208*1da177e4SLinus Torvalds /* proc file names */ 209*1da177e4SLinus Torvalds char fname[80]; 210*1da177e4SLinus Torvalds 211*1da177e4SLinus Torvalds struct pktgen_thread* pg_thread; /* the owner */ 212*1da177e4SLinus Torvalds struct pktgen_dev *next; /* Used for chaining in the thread's run-queue */ 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds int running; /* if this changes to false, the test will stop */ 215*1da177e4SLinus Torvalds 216*1da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 217*1da177e4SLinus Torvalds * we will do a random selection from within the range. 218*1da177e4SLinus Torvalds */ 219*1da177e4SLinus Torvalds __u32 flags; 220*1da177e4SLinus Torvalds 221*1da177e4SLinus Torvalds int min_pkt_size; /* = ETH_ZLEN; */ 222*1da177e4SLinus Torvalds int max_pkt_size; /* = ETH_ZLEN; */ 223*1da177e4SLinus Torvalds int nfrags; 224*1da177e4SLinus Torvalds __u32 delay_us; /* Default delay */ 225*1da177e4SLinus Torvalds __u32 delay_ns; 226*1da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 227*1da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 228*1da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 229*1da177e4SLinus Torvalds __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ 230*1da177e4SLinus Torvalds 231*1da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 232*1da177e4SLinus Torvalds __u64 next_tx_us; /* timestamp of when to tx next */ 233*1da177e4SLinus Torvalds __u32 next_tx_ns; 234*1da177e4SLinus Torvalds 235*1da177e4SLinus Torvalds __u64 allocated_skbs; 236*1da177e4SLinus Torvalds __u32 clone_count; 237*1da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 238*1da177e4SLinus Torvalds * Or a failed transmit of some sort? This will keep 239*1da177e4SLinus Torvalds * sequence numbers in order, for example. 240*1da177e4SLinus Torvalds */ 241*1da177e4SLinus Torvalds __u64 started_at; /* micro-seconds */ 242*1da177e4SLinus Torvalds __u64 stopped_at; /* micro-seconds */ 243*1da177e4SLinus Torvalds __u64 idle_acc; /* micro-seconds */ 244*1da177e4SLinus Torvalds __u32 seq_num; 245*1da177e4SLinus Torvalds 246*1da177e4SLinus Torvalds int clone_skb; /* Use multiple SKBs during packet gen. If this number 247*1da177e4SLinus Torvalds * is greater than 1, then that many coppies of the same 248*1da177e4SLinus Torvalds * packet will be sent before a new packet is allocated. 249*1da177e4SLinus Torvalds * For instance, if you want to send 1024 identical packets 250*1da177e4SLinus Torvalds * before creating a new packet, set clone_skb to 1024. 251*1da177e4SLinus Torvalds */ 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 254*1da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 255*1da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 256*1da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 257*1da177e4SLinus Torvalds 258*1da177e4SLinus Torvalds struct in6_addr in6_saddr; 259*1da177e4SLinus Torvalds struct in6_addr in6_daddr; 260*1da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 261*1da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 262*1da177e4SLinus Torvalds /* For ranges */ 263*1da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 264*1da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 265*1da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 266*1da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 267*1da177e4SLinus Torvalds 268*1da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 269*1da177e4SLinus Torvalds * defines the min/max for those ranges. 270*1da177e4SLinus Torvalds */ 271*1da177e4SLinus Torvalds __u32 saddr_min; /* inclusive, source IP address */ 272*1da177e4SLinus Torvalds __u32 saddr_max; /* exclusive, source IP address */ 273*1da177e4SLinus Torvalds __u32 daddr_min; /* inclusive, dest IP address */ 274*1da177e4SLinus Torvalds __u32 daddr_max; /* exclusive, dest IP address */ 275*1da177e4SLinus Torvalds 276*1da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 277*1da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 278*1da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 279*1da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 280*1da177e4SLinus Torvalds 281*1da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 282*1da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 283*1da177e4SLinus Torvalds 284*1da177e4SLinus Torvalds unsigned char dst_mac[6]; 285*1da177e4SLinus Torvalds unsigned char src_mac[6]; 286*1da177e4SLinus Torvalds 287*1da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 288*1da177e4SLinus Torvalds __u32 cur_src_mac_offset; 289*1da177e4SLinus Torvalds __u32 cur_saddr; 290*1da177e4SLinus Torvalds __u32 cur_daddr; 291*1da177e4SLinus Torvalds __u16 cur_udp_dst; 292*1da177e4SLinus Torvalds __u16 cur_udp_src; 293*1da177e4SLinus Torvalds __u32 cur_pkt_size; 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds __u8 hh[14]; 296*1da177e4SLinus Torvalds /* = { 297*1da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 298*1da177e4SLinus Torvalds 299*1da177e4SLinus Torvalds We fill in SRC address later 300*1da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 301*1da177e4SLinus Torvalds 0x08, 0x00 302*1da177e4SLinus Torvalds }; 303*1da177e4SLinus Torvalds */ 304*1da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 305*1da177e4SLinus Torvalds 306*1da177e4SLinus Torvalds struct sk_buff* skb; /* skb we are to transmit next, mainly used for when we 307*1da177e4SLinus Torvalds * are transmitting the same one multiple times 308*1da177e4SLinus Torvalds */ 309*1da177e4SLinus Torvalds struct net_device* odev; /* The out-going device. Note that the device should 310*1da177e4SLinus Torvalds * have it's pg_info pointer pointing back to this 311*1da177e4SLinus Torvalds * device. This will be set when the user specifies 312*1da177e4SLinus Torvalds * the out-going device name (not when the inject is 313*1da177e4SLinus Torvalds * started as it used to do.) 314*1da177e4SLinus Torvalds */ 315*1da177e4SLinus Torvalds struct flow_state *flows; 316*1da177e4SLinus Torvalds unsigned cflows; /* Concurrent flows (config) */ 317*1da177e4SLinus Torvalds unsigned lflow; /* Flow length (config) */ 318*1da177e4SLinus Torvalds unsigned nflows; /* accumulated flows (stats) */ 319*1da177e4SLinus Torvalds }; 320*1da177e4SLinus Torvalds 321*1da177e4SLinus Torvalds struct pktgen_hdr { 322*1da177e4SLinus Torvalds __u32 pgh_magic; 323*1da177e4SLinus Torvalds __u32 seq_num; 324*1da177e4SLinus Torvalds __u32 tv_sec; 325*1da177e4SLinus Torvalds __u32 tv_usec; 326*1da177e4SLinus Torvalds }; 327*1da177e4SLinus Torvalds 328*1da177e4SLinus Torvalds struct pktgen_thread { 329*1da177e4SLinus Torvalds spinlock_t if_lock; 330*1da177e4SLinus Torvalds struct pktgen_dev *if_list; /* All device here */ 331*1da177e4SLinus Torvalds struct pktgen_thread* next; 332*1da177e4SLinus Torvalds char name[32]; 333*1da177e4SLinus Torvalds char fname[128]; /* name of proc file */ 334*1da177e4SLinus Torvalds struct proc_dir_entry *proc_ent; 335*1da177e4SLinus Torvalds char result[512]; 336*1da177e4SLinus Torvalds u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ 337*1da177e4SLinus Torvalds 338*1da177e4SLinus Torvalds /* Field for thread to receive "posted" events terminate, stop ifs etc.*/ 339*1da177e4SLinus Torvalds 340*1da177e4SLinus Torvalds u32 control; 341*1da177e4SLinus Torvalds int pid; 342*1da177e4SLinus Torvalds int cpu; 343*1da177e4SLinus Torvalds 344*1da177e4SLinus Torvalds wait_queue_head_t queue; 345*1da177e4SLinus Torvalds }; 346*1da177e4SLinus Torvalds 347*1da177e4SLinus Torvalds #define REMOVE 1 348*1da177e4SLinus Torvalds #define FIND 0 349*1da177e4SLinus Torvalds 350*1da177e4SLinus Torvalds /* This code works around the fact that do_div cannot handle two 64-bit 351*1da177e4SLinus Torvalds numbers, and regular 64-bit division doesn't work on x86 kernels. 352*1da177e4SLinus Torvalds --Ben 353*1da177e4SLinus Torvalds */ 354*1da177e4SLinus Torvalds 355*1da177e4SLinus Torvalds #define PG_DIV 0 356*1da177e4SLinus Torvalds 357*1da177e4SLinus Torvalds /* This was emailed to LMKL by: Chris Caputo <ccaputo@alt.net> 358*1da177e4SLinus Torvalds * Function copied/adapted/optimized from: 359*1da177e4SLinus Torvalds * 360*1da177e4SLinus Torvalds * nemesis.sourceforge.net/browse/lib/static/intmath/ix86/intmath.c.html 361*1da177e4SLinus Torvalds * 362*1da177e4SLinus Torvalds * Copyright 1994, University of Cambridge Computer Laboratory 363*1da177e4SLinus Torvalds * All Rights Reserved. 364*1da177e4SLinus Torvalds * 365*1da177e4SLinus Torvalds */ 366*1da177e4SLinus Torvalds inline static s64 divremdi3(s64 x, s64 y, int type) 367*1da177e4SLinus Torvalds { 368*1da177e4SLinus Torvalds u64 a = (x < 0) ? -x : x; 369*1da177e4SLinus Torvalds u64 b = (y < 0) ? -y : y; 370*1da177e4SLinus Torvalds u64 res = 0, d = 1; 371*1da177e4SLinus Torvalds 372*1da177e4SLinus Torvalds if (b > 0) { 373*1da177e4SLinus Torvalds while (b < a) { 374*1da177e4SLinus Torvalds b <<= 1; 375*1da177e4SLinus Torvalds d <<= 1; 376*1da177e4SLinus Torvalds } 377*1da177e4SLinus Torvalds } 378*1da177e4SLinus Torvalds 379*1da177e4SLinus Torvalds do { 380*1da177e4SLinus Torvalds if ( a >= b ) { 381*1da177e4SLinus Torvalds a -= b; 382*1da177e4SLinus Torvalds res += d; 383*1da177e4SLinus Torvalds } 384*1da177e4SLinus Torvalds b >>= 1; 385*1da177e4SLinus Torvalds d >>= 1; 386*1da177e4SLinus Torvalds } 387*1da177e4SLinus Torvalds while (d); 388*1da177e4SLinus Torvalds 389*1da177e4SLinus Torvalds if (PG_DIV == type) { 390*1da177e4SLinus Torvalds return (((x ^ y) & (1ll<<63)) == 0) ? res : -(s64)res; 391*1da177e4SLinus Torvalds } 392*1da177e4SLinus Torvalds else { 393*1da177e4SLinus Torvalds return ((x & (1ll<<63)) == 0) ? a : -(s64)a; 394*1da177e4SLinus Torvalds } 395*1da177e4SLinus Torvalds } 396*1da177e4SLinus Torvalds 397*1da177e4SLinus Torvalds /* End of hacks to deal with 64-bit math on x86 */ 398*1da177e4SLinus Torvalds 399*1da177e4SLinus Torvalds /** Convert to miliseconds */ 400*1da177e4SLinus Torvalds static inline __u64 tv_to_ms(const struct timeval* tv) 401*1da177e4SLinus Torvalds { 402*1da177e4SLinus Torvalds __u64 ms = tv->tv_usec / 1000; 403*1da177e4SLinus Torvalds ms += (__u64)tv->tv_sec * (__u64)1000; 404*1da177e4SLinus Torvalds return ms; 405*1da177e4SLinus Torvalds } 406*1da177e4SLinus Torvalds 407*1da177e4SLinus Torvalds 408*1da177e4SLinus Torvalds /** Convert to micro-seconds */ 409*1da177e4SLinus Torvalds static inline __u64 tv_to_us(const struct timeval* tv) 410*1da177e4SLinus Torvalds { 411*1da177e4SLinus Torvalds __u64 us = tv->tv_usec; 412*1da177e4SLinus Torvalds us += (__u64)tv->tv_sec * (__u64)1000000; 413*1da177e4SLinus Torvalds return us; 414*1da177e4SLinus Torvalds } 415*1da177e4SLinus Torvalds 416*1da177e4SLinus Torvalds static inline __u64 pg_div(__u64 n, __u32 base) { 417*1da177e4SLinus Torvalds __u64 tmp = n; 418*1da177e4SLinus Torvalds do_div(tmp, base); 419*1da177e4SLinus Torvalds /* printk("pktgen: pg_div, n: %llu base: %d rv: %llu\n", 420*1da177e4SLinus Torvalds n, base, tmp); */ 421*1da177e4SLinus Torvalds return tmp; 422*1da177e4SLinus Torvalds } 423*1da177e4SLinus Torvalds 424*1da177e4SLinus Torvalds static inline __u64 pg_div64(__u64 n, __u64 base) 425*1da177e4SLinus Torvalds { 426*1da177e4SLinus Torvalds __u64 tmp = n; 427*1da177e4SLinus Torvalds /* 428*1da177e4SLinus Torvalds * How do we know if the architectrure we are running on 429*1da177e4SLinus Torvalds * supports division with 64 bit base? 430*1da177e4SLinus Torvalds * 431*1da177e4SLinus Torvalds */ 432*1da177e4SLinus Torvalds #if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__) 433*1da177e4SLinus Torvalds 434*1da177e4SLinus Torvalds do_div(tmp, base); 435*1da177e4SLinus Torvalds #else 436*1da177e4SLinus Torvalds tmp = divremdi3(n, base, PG_DIV); 437*1da177e4SLinus Torvalds #endif 438*1da177e4SLinus Torvalds return tmp; 439*1da177e4SLinus Torvalds } 440*1da177e4SLinus Torvalds 441*1da177e4SLinus Torvalds static inline u32 pktgen_random(void) 442*1da177e4SLinus Torvalds { 443*1da177e4SLinus Torvalds #if 0 444*1da177e4SLinus Torvalds __u32 n; 445*1da177e4SLinus Torvalds get_random_bytes(&n, 4); 446*1da177e4SLinus Torvalds return n; 447*1da177e4SLinus Torvalds #else 448*1da177e4SLinus Torvalds return net_random(); 449*1da177e4SLinus Torvalds #endif 450*1da177e4SLinus Torvalds } 451*1da177e4SLinus Torvalds 452*1da177e4SLinus Torvalds static inline __u64 getCurMs(void) 453*1da177e4SLinus Torvalds { 454*1da177e4SLinus Torvalds struct timeval tv; 455*1da177e4SLinus Torvalds do_gettimeofday(&tv); 456*1da177e4SLinus Torvalds return tv_to_ms(&tv); 457*1da177e4SLinus Torvalds } 458*1da177e4SLinus Torvalds 459*1da177e4SLinus Torvalds static inline __u64 getCurUs(void) 460*1da177e4SLinus Torvalds { 461*1da177e4SLinus Torvalds struct timeval tv; 462*1da177e4SLinus Torvalds do_gettimeofday(&tv); 463*1da177e4SLinus Torvalds return tv_to_us(&tv); 464*1da177e4SLinus Torvalds } 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds static inline __u64 tv_diff(const struct timeval* a, const struct timeval* b) 467*1da177e4SLinus Torvalds { 468*1da177e4SLinus Torvalds return tv_to_us(a) - tv_to_us(b); 469*1da177e4SLinus Torvalds } 470*1da177e4SLinus Torvalds 471*1da177e4SLinus Torvalds 472*1da177e4SLinus Torvalds /* old include end */ 473*1da177e4SLinus Torvalds 474*1da177e4SLinus Torvalds static char version[] __initdata = VERSION; 475*1da177e4SLinus Torvalds 476*1da177e4SLinus Torvalds static ssize_t proc_pgctrl_read(struct file* file, char __user * buf, size_t count, loff_t *ppos); 477*1da177e4SLinus Torvalds static ssize_t proc_pgctrl_write(struct file* file, const char __user * buf, size_t count, loff_t *ppos); 478*1da177e4SLinus Torvalds static int proc_if_read(char *buf , char **start, off_t offset, int len, int *eof, void *data); 479*1da177e4SLinus Torvalds 480*1da177e4SLinus Torvalds static int proc_thread_read(char *buf , char **start, off_t offset, int len, int *eof, void *data); 481*1da177e4SLinus Torvalds static int proc_if_write(struct file *file, const char __user *user_buffer, unsigned long count, void *data); 482*1da177e4SLinus Torvalds static int proc_thread_write(struct file *file, const char __user *user_buffer, unsigned long count, void *data); 483*1da177e4SLinus Torvalds static int create_proc_dir(void); 484*1da177e4SLinus Torvalds static int remove_proc_dir(void); 485*1da177e4SLinus Torvalds 486*1da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread* t, struct pktgen_dev *i); 487*1da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread* t, const char* ifname); 488*1da177e4SLinus Torvalds static struct pktgen_thread* pktgen_find_thread(const char* name); 489*1da177e4SLinus Torvalds static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread* t, const char* ifname); 490*1da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 491*1da177e4SLinus Torvalds static void pktgen_run_all_threads(void); 492*1da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void); 493*1da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev); 494*1da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread* t); 495*1da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 496*1da177e4SLinus Torvalds static struct pktgen_dev *pktgen_NN_threads(const char* dev_name, int remove); 497*1da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s,char ip[16]); 498*1da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s,const char ip[16]); 499*1da177e4SLinus Torvalds 500*1da177e4SLinus Torvalds /* Module parameters, defaults. */ 501*1da177e4SLinus Torvalds static int pg_count_d = 1000; /* 1000 pkts by default */ 502*1da177e4SLinus Torvalds static int pg_delay_d = 0; 503*1da177e4SLinus Torvalds static int pg_clone_skb_d = 0; 504*1da177e4SLinus Torvalds static int debug = 0; 505*1da177e4SLinus Torvalds 506*1da177e4SLinus Torvalds static spinlock_t _thread_lock = SPIN_LOCK_UNLOCKED; 507*1da177e4SLinus Torvalds static struct pktgen_thread *pktgen_threads = NULL; 508*1da177e4SLinus Torvalds 509*1da177e4SLinus Torvalds static char module_fname[128]; 510*1da177e4SLinus Torvalds static struct proc_dir_entry *module_proc_ent = NULL; 511*1da177e4SLinus Torvalds 512*1da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 513*1da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 514*1da177e4SLinus Torvalds }; 515*1da177e4SLinus Torvalds 516*1da177e4SLinus Torvalds static struct file_operations pktgen_fops = { 517*1da177e4SLinus Torvalds .read = proc_pgctrl_read, 518*1da177e4SLinus Torvalds .write = proc_pgctrl_write, 519*1da177e4SLinus Torvalds /* .ioctl = pktgen_ioctl, later maybe */ 520*1da177e4SLinus Torvalds }; 521*1da177e4SLinus Torvalds 522*1da177e4SLinus Torvalds /* 523*1da177e4SLinus Torvalds * /proc handling functions 524*1da177e4SLinus Torvalds * 525*1da177e4SLinus Torvalds */ 526*1da177e4SLinus Torvalds 527*1da177e4SLinus Torvalds static struct proc_dir_entry *pg_proc_dir = NULL; 528*1da177e4SLinus Torvalds static int proc_pgctrl_read_eof=0; 529*1da177e4SLinus Torvalds 530*1da177e4SLinus Torvalds static ssize_t proc_pgctrl_read(struct file* file, char __user * buf, 531*1da177e4SLinus Torvalds size_t count, loff_t *ppos) 532*1da177e4SLinus Torvalds { 533*1da177e4SLinus Torvalds char data[200]; 534*1da177e4SLinus Torvalds int len = 0; 535*1da177e4SLinus Torvalds 536*1da177e4SLinus Torvalds if(proc_pgctrl_read_eof) { 537*1da177e4SLinus Torvalds proc_pgctrl_read_eof=0; 538*1da177e4SLinus Torvalds len = 0; 539*1da177e4SLinus Torvalds goto out; 540*1da177e4SLinus Torvalds } 541*1da177e4SLinus Torvalds 542*1da177e4SLinus Torvalds sprintf(data, "%s", VERSION); 543*1da177e4SLinus Torvalds 544*1da177e4SLinus Torvalds len = strlen(data); 545*1da177e4SLinus Torvalds 546*1da177e4SLinus Torvalds if(len > count) { 547*1da177e4SLinus Torvalds len =-EFAULT; 548*1da177e4SLinus Torvalds goto out; 549*1da177e4SLinus Torvalds } 550*1da177e4SLinus Torvalds 551*1da177e4SLinus Torvalds if (copy_to_user(buf, data, len)) { 552*1da177e4SLinus Torvalds len =-EFAULT; 553*1da177e4SLinus Torvalds goto out; 554*1da177e4SLinus Torvalds } 555*1da177e4SLinus Torvalds 556*1da177e4SLinus Torvalds *ppos += len; 557*1da177e4SLinus Torvalds proc_pgctrl_read_eof=1; /* EOF next call */ 558*1da177e4SLinus Torvalds 559*1da177e4SLinus Torvalds out: 560*1da177e4SLinus Torvalds return len; 561*1da177e4SLinus Torvalds } 562*1da177e4SLinus Torvalds 563*1da177e4SLinus Torvalds static ssize_t proc_pgctrl_write(struct file* file,const char __user * buf, 564*1da177e4SLinus Torvalds size_t count, loff_t *ppos) 565*1da177e4SLinus Torvalds { 566*1da177e4SLinus Torvalds char *data = NULL; 567*1da177e4SLinus Torvalds int err = 0; 568*1da177e4SLinus Torvalds 569*1da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)){ 570*1da177e4SLinus Torvalds err = -EPERM; 571*1da177e4SLinus Torvalds goto out; 572*1da177e4SLinus Torvalds } 573*1da177e4SLinus Torvalds 574*1da177e4SLinus Torvalds data = (void*)vmalloc ((unsigned int)count); 575*1da177e4SLinus Torvalds 576*1da177e4SLinus Torvalds if(!data) { 577*1da177e4SLinus Torvalds err = -ENOMEM; 578*1da177e4SLinus Torvalds goto out; 579*1da177e4SLinus Torvalds } 580*1da177e4SLinus Torvalds if (copy_from_user(data, buf, count)) { 581*1da177e4SLinus Torvalds err =-EFAULT; 582*1da177e4SLinus Torvalds goto out_free; 583*1da177e4SLinus Torvalds } 584*1da177e4SLinus Torvalds data[count-1] = 0; /* Make string */ 585*1da177e4SLinus Torvalds 586*1da177e4SLinus Torvalds if (!strcmp(data, "stop")) 587*1da177e4SLinus Torvalds pktgen_stop_all_threads_ifs(); 588*1da177e4SLinus Torvalds 589*1da177e4SLinus Torvalds else if (!strcmp(data, "start")) 590*1da177e4SLinus Torvalds pktgen_run_all_threads(); 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds else 593*1da177e4SLinus Torvalds printk("pktgen: Unknown command: %s\n", data); 594*1da177e4SLinus Torvalds 595*1da177e4SLinus Torvalds err = count; 596*1da177e4SLinus Torvalds 597*1da177e4SLinus Torvalds out_free: 598*1da177e4SLinus Torvalds vfree (data); 599*1da177e4SLinus Torvalds out: 600*1da177e4SLinus Torvalds return err; 601*1da177e4SLinus Torvalds } 602*1da177e4SLinus Torvalds 603*1da177e4SLinus Torvalds static int proc_if_read(char *buf , char **start, off_t offset, 604*1da177e4SLinus Torvalds int len, int *eof, void *data) 605*1da177e4SLinus Torvalds { 606*1da177e4SLinus Torvalds char *p; 607*1da177e4SLinus Torvalds int i; 608*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data); 609*1da177e4SLinus Torvalds __u64 sa; 610*1da177e4SLinus Torvalds __u64 stopped; 611*1da177e4SLinus Torvalds __u64 now = getCurUs(); 612*1da177e4SLinus Torvalds 613*1da177e4SLinus Torvalds p = buf; 614*1da177e4SLinus Torvalds p += sprintf(p, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 615*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->count, 616*1da177e4SLinus Torvalds pkt_dev->min_pkt_size, pkt_dev->max_pkt_size); 617*1da177e4SLinus Torvalds 618*1da177e4SLinus Torvalds p += sprintf(p, " frags: %d delay: %u clone_skb: %d ifname: %s\n", 619*1da177e4SLinus Torvalds pkt_dev->nfrags, 1000*pkt_dev->delay_us+pkt_dev->delay_ns, pkt_dev->clone_skb, pkt_dev->ifname); 620*1da177e4SLinus Torvalds 621*1da177e4SLinus Torvalds p += sprintf(p, " flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow); 622*1da177e4SLinus Torvalds 623*1da177e4SLinus Torvalds 624*1da177e4SLinus Torvalds if(pkt_dev->flags & F_IPV6) { 625*1da177e4SLinus Torvalds char b1[128], b2[128], b3[128]; 626*1da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); 627*1da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); 628*1da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); 629*1da177e4SLinus Torvalds p += sprintf(p, " saddr: %s min_saddr: %s max_saddr: %s\n", b1, b2, b3); 630*1da177e4SLinus Torvalds 631*1da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); 632*1da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); 633*1da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); 634*1da177e4SLinus Torvalds p += sprintf(p, " daddr: %s min_daddr: %s max_daddr: %s\n", b1, b2, b3); 635*1da177e4SLinus Torvalds 636*1da177e4SLinus Torvalds } 637*1da177e4SLinus Torvalds else 638*1da177e4SLinus Torvalds p += sprintf(p, " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", 639*1da177e4SLinus Torvalds pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, pkt_dev->src_max); 640*1da177e4SLinus Torvalds 641*1da177e4SLinus Torvalds p += sprintf(p, " src_mac: "); 642*1da177e4SLinus Torvalds 643*1da177e4SLinus Torvalds if ((pkt_dev->src_mac[0] == 0) && 644*1da177e4SLinus Torvalds (pkt_dev->src_mac[1] == 0) && 645*1da177e4SLinus Torvalds (pkt_dev->src_mac[2] == 0) && 646*1da177e4SLinus Torvalds (pkt_dev->src_mac[3] == 0) && 647*1da177e4SLinus Torvalds (pkt_dev->src_mac[4] == 0) && 648*1da177e4SLinus Torvalds (pkt_dev->src_mac[5] == 0)) 649*1da177e4SLinus Torvalds 650*1da177e4SLinus Torvalds for (i = 0; i < 6; i++) 651*1da177e4SLinus Torvalds p += sprintf(p, "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? " " : ":"); 652*1da177e4SLinus Torvalds 653*1da177e4SLinus Torvalds else 654*1da177e4SLinus Torvalds for (i = 0; i < 6; i++) 655*1da177e4SLinus Torvalds p += sprintf(p, "%02X%s", pkt_dev->src_mac[i], i == 5 ? " " : ":"); 656*1da177e4SLinus Torvalds 657*1da177e4SLinus Torvalds p += sprintf(p, "dst_mac: "); 658*1da177e4SLinus Torvalds for (i = 0; i < 6; i++) 659*1da177e4SLinus Torvalds p += sprintf(p, "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":"); 660*1da177e4SLinus Torvalds 661*1da177e4SLinus Torvalds p += sprintf(p, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", 662*1da177e4SLinus Torvalds pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min, 663*1da177e4SLinus Torvalds pkt_dev->udp_dst_max); 664*1da177e4SLinus Torvalds 665*1da177e4SLinus Torvalds p += sprintf(p, " src_mac_count: %d dst_mac_count: %d \n Flags: ", 666*1da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 667*1da177e4SLinus Torvalds 668*1da177e4SLinus Torvalds 669*1da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 670*1da177e4SLinus Torvalds p += sprintf(p, "IPV6 "); 671*1da177e4SLinus Torvalds 672*1da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 673*1da177e4SLinus Torvalds p += sprintf(p, "IPSRC_RND "); 674*1da177e4SLinus Torvalds 675*1da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 676*1da177e4SLinus Torvalds p += sprintf(p, "IPDST_RND "); 677*1da177e4SLinus Torvalds 678*1da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 679*1da177e4SLinus Torvalds p += sprintf(p, "TXSIZE_RND "); 680*1da177e4SLinus Torvalds 681*1da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 682*1da177e4SLinus Torvalds p += sprintf(p, "UDPSRC_RND "); 683*1da177e4SLinus Torvalds 684*1da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 685*1da177e4SLinus Torvalds p += sprintf(p, "UDPDST_RND "); 686*1da177e4SLinus Torvalds 687*1da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 688*1da177e4SLinus Torvalds p += sprintf(p, "MACSRC_RND "); 689*1da177e4SLinus Torvalds 690*1da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 691*1da177e4SLinus Torvalds p += sprintf(p, "MACDST_RND "); 692*1da177e4SLinus Torvalds 693*1da177e4SLinus Torvalds 694*1da177e4SLinus Torvalds p += sprintf(p, "\n"); 695*1da177e4SLinus Torvalds 696*1da177e4SLinus Torvalds sa = pkt_dev->started_at; 697*1da177e4SLinus Torvalds stopped = pkt_dev->stopped_at; 698*1da177e4SLinus Torvalds if (pkt_dev->running) 699*1da177e4SLinus Torvalds stopped = now; /* not really stopped, more like last-running-at */ 700*1da177e4SLinus Torvalds 701*1da177e4SLinus Torvalds p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", 702*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->sofar, 703*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->errors, 704*1da177e4SLinus Torvalds (unsigned long long) sa, 705*1da177e4SLinus Torvalds (unsigned long long) stopped, 706*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->idle_acc); 707*1da177e4SLinus Torvalds 708*1da177e4SLinus Torvalds p += sprintf(p, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 709*1da177e4SLinus Torvalds pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, pkt_dev->cur_src_mac_offset); 710*1da177e4SLinus Torvalds 711*1da177e4SLinus Torvalds if(pkt_dev->flags & F_IPV6) { 712*1da177e4SLinus Torvalds char b1[128], b2[128]; 713*1da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); 714*1da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); 715*1da177e4SLinus Torvalds p += sprintf(p, " cur_saddr: %s cur_daddr: %s\n", b2, b1); 716*1da177e4SLinus Torvalds } 717*1da177e4SLinus Torvalds else 718*1da177e4SLinus Torvalds p += sprintf(p, " cur_saddr: 0x%x cur_daddr: 0x%x\n", 719*1da177e4SLinus Torvalds pkt_dev->cur_saddr, pkt_dev->cur_daddr); 720*1da177e4SLinus Torvalds 721*1da177e4SLinus Torvalds 722*1da177e4SLinus Torvalds p += sprintf(p, " cur_udp_dst: %d cur_udp_src: %d\n", 723*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 724*1da177e4SLinus Torvalds 725*1da177e4SLinus Torvalds p += sprintf(p, " flows: %u\n", pkt_dev->nflows); 726*1da177e4SLinus Torvalds 727*1da177e4SLinus Torvalds if (pkt_dev->result[0]) 728*1da177e4SLinus Torvalds p += sprintf(p, "Result: %s\n", pkt_dev->result); 729*1da177e4SLinus Torvalds else 730*1da177e4SLinus Torvalds p += sprintf(p, "Result: Idle\n"); 731*1da177e4SLinus Torvalds *eof = 1; 732*1da177e4SLinus Torvalds 733*1da177e4SLinus Torvalds return p - buf; 734*1da177e4SLinus Torvalds } 735*1da177e4SLinus Torvalds 736*1da177e4SLinus Torvalds 737*1da177e4SLinus Torvalds static int count_trail_chars(const char __user *user_buffer, unsigned int maxlen) 738*1da177e4SLinus Torvalds { 739*1da177e4SLinus Torvalds int i; 740*1da177e4SLinus Torvalds 741*1da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 742*1da177e4SLinus Torvalds char c; 743*1da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 744*1da177e4SLinus Torvalds return -EFAULT; 745*1da177e4SLinus Torvalds switch (c) { 746*1da177e4SLinus Torvalds case '\"': 747*1da177e4SLinus Torvalds case '\n': 748*1da177e4SLinus Torvalds case '\r': 749*1da177e4SLinus Torvalds case '\t': 750*1da177e4SLinus Torvalds case ' ': 751*1da177e4SLinus Torvalds case '=': 752*1da177e4SLinus Torvalds break; 753*1da177e4SLinus Torvalds default: 754*1da177e4SLinus Torvalds goto done; 755*1da177e4SLinus Torvalds }; 756*1da177e4SLinus Torvalds } 757*1da177e4SLinus Torvalds done: 758*1da177e4SLinus Torvalds return i; 759*1da177e4SLinus Torvalds } 760*1da177e4SLinus Torvalds 761*1da177e4SLinus Torvalds static unsigned long num_arg(const char __user *user_buffer, unsigned long maxlen, 762*1da177e4SLinus Torvalds unsigned long *num) 763*1da177e4SLinus Torvalds { 764*1da177e4SLinus Torvalds int i = 0; 765*1da177e4SLinus Torvalds *num = 0; 766*1da177e4SLinus Torvalds 767*1da177e4SLinus Torvalds for(; i < maxlen; i++) { 768*1da177e4SLinus Torvalds char c; 769*1da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 770*1da177e4SLinus Torvalds return -EFAULT; 771*1da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 772*1da177e4SLinus Torvalds *num *= 10; 773*1da177e4SLinus Torvalds *num += c -'0'; 774*1da177e4SLinus Torvalds } else 775*1da177e4SLinus Torvalds break; 776*1da177e4SLinus Torvalds } 777*1da177e4SLinus Torvalds return i; 778*1da177e4SLinus Torvalds } 779*1da177e4SLinus Torvalds 780*1da177e4SLinus Torvalds static int strn_len(const char __user *user_buffer, unsigned int maxlen) 781*1da177e4SLinus Torvalds { 782*1da177e4SLinus Torvalds int i = 0; 783*1da177e4SLinus Torvalds 784*1da177e4SLinus Torvalds for(; i < maxlen; i++) { 785*1da177e4SLinus Torvalds char c; 786*1da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 787*1da177e4SLinus Torvalds return -EFAULT; 788*1da177e4SLinus Torvalds switch (c) { 789*1da177e4SLinus Torvalds case '\"': 790*1da177e4SLinus Torvalds case '\n': 791*1da177e4SLinus Torvalds case '\r': 792*1da177e4SLinus Torvalds case '\t': 793*1da177e4SLinus Torvalds case ' ': 794*1da177e4SLinus Torvalds goto done_str; 795*1da177e4SLinus Torvalds break; 796*1da177e4SLinus Torvalds default: 797*1da177e4SLinus Torvalds break; 798*1da177e4SLinus Torvalds }; 799*1da177e4SLinus Torvalds } 800*1da177e4SLinus Torvalds done_str: 801*1da177e4SLinus Torvalds 802*1da177e4SLinus Torvalds return i; 803*1da177e4SLinus Torvalds } 804*1da177e4SLinus Torvalds 805*1da177e4SLinus Torvalds static int proc_if_write(struct file *file, const char __user *user_buffer, 806*1da177e4SLinus Torvalds unsigned long count, void *data) 807*1da177e4SLinus Torvalds { 808*1da177e4SLinus Torvalds int i = 0, max, len; 809*1da177e4SLinus Torvalds char name[16], valstr[32]; 810*1da177e4SLinus Torvalds unsigned long value = 0; 811*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data); 812*1da177e4SLinus Torvalds char* pg_result = NULL; 813*1da177e4SLinus Torvalds int tmp = 0; 814*1da177e4SLinus Torvalds char buf[128]; 815*1da177e4SLinus Torvalds 816*1da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 817*1da177e4SLinus Torvalds 818*1da177e4SLinus Torvalds if (count < 1) { 819*1da177e4SLinus Torvalds printk("pktgen: wrong command format\n"); 820*1da177e4SLinus Torvalds return -EINVAL; 821*1da177e4SLinus Torvalds } 822*1da177e4SLinus Torvalds 823*1da177e4SLinus Torvalds max = count - i; 824*1da177e4SLinus Torvalds tmp = count_trail_chars(&user_buffer[i], max); 825*1da177e4SLinus Torvalds if (tmp < 0) { 826*1da177e4SLinus Torvalds printk("pktgen: illegal format\n"); 827*1da177e4SLinus Torvalds return tmp; 828*1da177e4SLinus Torvalds } 829*1da177e4SLinus Torvalds i += tmp; 830*1da177e4SLinus Torvalds 831*1da177e4SLinus Torvalds /* Read variable name */ 832*1da177e4SLinus Torvalds 833*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 834*1da177e4SLinus Torvalds if (len < 0) { return len; } 835*1da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 836*1da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len) ) 837*1da177e4SLinus Torvalds return -EFAULT; 838*1da177e4SLinus Torvalds i += len; 839*1da177e4SLinus Torvalds 840*1da177e4SLinus Torvalds max = count -i; 841*1da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 842*1da177e4SLinus Torvalds if (len < 0) 843*1da177e4SLinus Torvalds return len; 844*1da177e4SLinus Torvalds 845*1da177e4SLinus Torvalds i += len; 846*1da177e4SLinus Torvalds 847*1da177e4SLinus Torvalds if (debug) { 848*1da177e4SLinus Torvalds char tb[count + 1]; 849*1da177e4SLinus Torvalds if (copy_from_user(tb, user_buffer, count)) 850*1da177e4SLinus Torvalds return -EFAULT; 851*1da177e4SLinus Torvalds tb[count] = 0; 852*1da177e4SLinus Torvalds printk("pktgen: %s,%lu buffer -:%s:-\n", name, count, tb); 853*1da177e4SLinus Torvalds } 854*1da177e4SLinus Torvalds 855*1da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 856*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 857*1da177e4SLinus Torvalds if (len < 0) { return len; } 858*1da177e4SLinus Torvalds i += len; 859*1da177e4SLinus Torvalds if (value < 14+20+8) 860*1da177e4SLinus Torvalds value = 14+20+8; 861*1da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 862*1da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 863*1da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 864*1da177e4SLinus Torvalds } 865*1da177e4SLinus Torvalds sprintf(pg_result, "OK: min_pkt_size=%u", pkt_dev->min_pkt_size); 866*1da177e4SLinus Torvalds return count; 867*1da177e4SLinus Torvalds } 868*1da177e4SLinus Torvalds 869*1da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 870*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 871*1da177e4SLinus Torvalds if (len < 0) { return len; } 872*1da177e4SLinus Torvalds i += len; 873*1da177e4SLinus Torvalds if (value < 14+20+8) 874*1da177e4SLinus Torvalds value = 14+20+8; 875*1da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 876*1da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 877*1da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 878*1da177e4SLinus Torvalds } 879*1da177e4SLinus Torvalds sprintf(pg_result, "OK: max_pkt_size=%u", pkt_dev->max_pkt_size); 880*1da177e4SLinus Torvalds return count; 881*1da177e4SLinus Torvalds } 882*1da177e4SLinus Torvalds 883*1da177e4SLinus Torvalds /* Shortcut for min = max */ 884*1da177e4SLinus Torvalds 885*1da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 886*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 887*1da177e4SLinus Torvalds if (len < 0) { return len; } 888*1da177e4SLinus Torvalds i += len; 889*1da177e4SLinus Torvalds if (value < 14+20+8) 890*1da177e4SLinus Torvalds value = 14+20+8; 891*1da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 892*1da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 893*1da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 894*1da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 895*1da177e4SLinus Torvalds } 896*1da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 897*1da177e4SLinus Torvalds return count; 898*1da177e4SLinus Torvalds } 899*1da177e4SLinus Torvalds 900*1da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 901*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 902*1da177e4SLinus Torvalds if (len < 0) { return len; } 903*1da177e4SLinus Torvalds i += len; 904*1da177e4SLinus Torvalds debug = value; 905*1da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 906*1da177e4SLinus Torvalds return count; 907*1da177e4SLinus Torvalds } 908*1da177e4SLinus Torvalds 909*1da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 910*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 911*1da177e4SLinus Torvalds if (len < 0) { return len; } 912*1da177e4SLinus Torvalds i += len; 913*1da177e4SLinus Torvalds pkt_dev->nfrags = value; 914*1da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 915*1da177e4SLinus Torvalds return count; 916*1da177e4SLinus Torvalds } 917*1da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 918*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 919*1da177e4SLinus Torvalds if (len < 0) { return len; } 920*1da177e4SLinus Torvalds i += len; 921*1da177e4SLinus Torvalds if (value == 0x7FFFFFFF) { 922*1da177e4SLinus Torvalds pkt_dev->delay_us = 0x7FFFFFFF; 923*1da177e4SLinus Torvalds pkt_dev->delay_ns = 0; 924*1da177e4SLinus Torvalds } else { 925*1da177e4SLinus Torvalds pkt_dev->delay_us = value / 1000; 926*1da177e4SLinus Torvalds pkt_dev->delay_ns = value % 1000; 927*1da177e4SLinus Torvalds } 928*1da177e4SLinus Torvalds sprintf(pg_result, "OK: delay=%u", 1000*pkt_dev->delay_us+pkt_dev->delay_ns); 929*1da177e4SLinus Torvalds return count; 930*1da177e4SLinus Torvalds } 931*1da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 932*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 933*1da177e4SLinus Torvalds if (len < 0) { return len; } 934*1da177e4SLinus Torvalds i += len; 935*1da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 936*1da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 937*1da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 938*1da177e4SLinus Torvalds } 939*1da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 940*1da177e4SLinus Torvalds return count; 941*1da177e4SLinus Torvalds } 942*1da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 943*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 944*1da177e4SLinus Torvalds if (len < 0) { return len; } 945*1da177e4SLinus Torvalds i += len; 946*1da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 947*1da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 948*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 949*1da177e4SLinus Torvalds } 950*1da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 951*1da177e4SLinus Torvalds return count; 952*1da177e4SLinus Torvalds } 953*1da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 954*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 955*1da177e4SLinus Torvalds if (len < 0) { return len; } 956*1da177e4SLinus Torvalds i += len; 957*1da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 958*1da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 959*1da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 960*1da177e4SLinus Torvalds } 961*1da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 962*1da177e4SLinus Torvalds return count; 963*1da177e4SLinus Torvalds } 964*1da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 965*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 966*1da177e4SLinus Torvalds if (len < 0) { return len; } 967*1da177e4SLinus Torvalds i += len; 968*1da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 969*1da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 970*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 971*1da177e4SLinus Torvalds } 972*1da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 973*1da177e4SLinus Torvalds return count; 974*1da177e4SLinus Torvalds } 975*1da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 976*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 977*1da177e4SLinus Torvalds if (len < 0) { return len; } 978*1da177e4SLinus Torvalds i += len; 979*1da177e4SLinus Torvalds pkt_dev->clone_skb = value; 980*1da177e4SLinus Torvalds 981*1da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 982*1da177e4SLinus Torvalds return count; 983*1da177e4SLinus Torvalds } 984*1da177e4SLinus Torvalds if (!strcmp(name, "count")) { 985*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 986*1da177e4SLinus Torvalds if (len < 0) { return len; } 987*1da177e4SLinus Torvalds i += len; 988*1da177e4SLinus Torvalds pkt_dev->count = value; 989*1da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 990*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->count); 991*1da177e4SLinus Torvalds return count; 992*1da177e4SLinus Torvalds } 993*1da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 994*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 995*1da177e4SLinus Torvalds if (len < 0) { return len; } 996*1da177e4SLinus Torvalds i += len; 997*1da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 998*1da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 999*1da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 1000*1da177e4SLinus Torvalds } 1001*1da177e4SLinus Torvalds sprintf(pg_result, "OK: src_mac_count=%d", pkt_dev->src_mac_count); 1002*1da177e4SLinus Torvalds return count; 1003*1da177e4SLinus Torvalds } 1004*1da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 1005*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1006*1da177e4SLinus Torvalds if (len < 0) { return len; } 1007*1da177e4SLinus Torvalds i += len; 1008*1da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 1009*1da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 1010*1da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 1011*1da177e4SLinus Torvalds } 1012*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_mac_count=%d", pkt_dev->dst_mac_count); 1013*1da177e4SLinus Torvalds return count; 1014*1da177e4SLinus Torvalds } 1015*1da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 1016*1da177e4SLinus Torvalds char f[32]; 1017*1da177e4SLinus Torvalds memset(f, 0, 32); 1018*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 1019*1da177e4SLinus Torvalds if (len < 0) { return len; } 1020*1da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 1021*1da177e4SLinus Torvalds return -EFAULT; 1022*1da177e4SLinus Torvalds i += len; 1023*1da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 1024*1da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 1025*1da177e4SLinus Torvalds 1026*1da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 1027*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 1028*1da177e4SLinus Torvalds 1029*1da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 1030*1da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 1031*1da177e4SLinus Torvalds 1032*1da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 1033*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 1034*1da177e4SLinus Torvalds 1035*1da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 1036*1da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 1037*1da177e4SLinus Torvalds 1038*1da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 1039*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 1040*1da177e4SLinus Torvalds 1041*1da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 1042*1da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 1043*1da177e4SLinus Torvalds 1044*1da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 1045*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 1046*1da177e4SLinus Torvalds 1047*1da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 1048*1da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 1049*1da177e4SLinus Torvalds 1050*1da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 1051*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 1052*1da177e4SLinus Torvalds 1053*1da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 1054*1da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 1055*1da177e4SLinus Torvalds 1056*1da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 1057*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 1058*1da177e4SLinus Torvalds 1059*1da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 1060*1da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 1061*1da177e4SLinus Torvalds 1062*1da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 1063*1da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 1064*1da177e4SLinus Torvalds 1065*1da177e4SLinus Torvalds else { 1066*1da177e4SLinus Torvalds sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 1067*1da177e4SLinus Torvalds f, 1068*1da177e4SLinus Torvalds "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); 1069*1da177e4SLinus Torvalds return count; 1070*1da177e4SLinus Torvalds } 1071*1da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 1072*1da177e4SLinus Torvalds return count; 1073*1da177e4SLinus Torvalds } 1074*1da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 1075*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 1076*1da177e4SLinus Torvalds if (len < 0) { return len; } 1077*1da177e4SLinus Torvalds 1078*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1079*1da177e4SLinus Torvalds return -EFAULT; 1080*1da177e4SLinus Torvalds buf[len] = 0; 1081*1da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 1082*1da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 1083*1da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 1084*1da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 1085*1da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 1086*1da177e4SLinus Torvalds } 1087*1da177e4SLinus Torvalds if(debug) 1088*1da177e4SLinus Torvalds printk("pktgen: dst_min set to: %s\n", pkt_dev->dst_min); 1089*1da177e4SLinus Torvalds i += len; 1090*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 1091*1da177e4SLinus Torvalds return count; 1092*1da177e4SLinus Torvalds } 1093*1da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 1094*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 1095*1da177e4SLinus Torvalds if (len < 0) { return len; } 1096*1da177e4SLinus Torvalds 1097*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1098*1da177e4SLinus Torvalds return -EFAULT; 1099*1da177e4SLinus Torvalds 1100*1da177e4SLinus Torvalds buf[len] = 0; 1101*1da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 1102*1da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 1103*1da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 1104*1da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 1105*1da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 1106*1da177e4SLinus Torvalds } 1107*1da177e4SLinus Torvalds if(debug) 1108*1da177e4SLinus Torvalds printk("pktgen: dst_max set to: %s\n", pkt_dev->dst_max); 1109*1da177e4SLinus Torvalds i += len; 1110*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 1111*1da177e4SLinus Torvalds return count; 1112*1da177e4SLinus Torvalds } 1113*1da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 1114*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1115*1da177e4SLinus Torvalds if (len < 0) return len; 1116*1da177e4SLinus Torvalds 1117*1da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 1118*1da177e4SLinus Torvalds 1119*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1120*1da177e4SLinus Torvalds return -EFAULT; 1121*1da177e4SLinus Torvalds buf[len] = 0; 1122*1da177e4SLinus Torvalds 1123*1da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); 1124*1da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); 1125*1da177e4SLinus Torvalds 1126*1da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); 1127*1da177e4SLinus Torvalds 1128*1da177e4SLinus Torvalds if(debug) 1129*1da177e4SLinus Torvalds printk("pktgen: dst6 set to: %s\n", buf); 1130*1da177e4SLinus Torvalds 1131*1da177e4SLinus Torvalds i += len; 1132*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 1133*1da177e4SLinus Torvalds return count; 1134*1da177e4SLinus Torvalds } 1135*1da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 1136*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1137*1da177e4SLinus Torvalds if (len < 0) return len; 1138*1da177e4SLinus Torvalds 1139*1da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 1140*1da177e4SLinus Torvalds 1141*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1142*1da177e4SLinus Torvalds return -EFAULT; 1143*1da177e4SLinus Torvalds buf[len] = 0; 1144*1da177e4SLinus Torvalds 1145*1da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 1146*1da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 1147*1da177e4SLinus Torvalds 1148*1da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->min_in6_daddr); 1149*1da177e4SLinus Torvalds if(debug) 1150*1da177e4SLinus Torvalds printk("pktgen: dst6_min set to: %s\n", buf); 1151*1da177e4SLinus Torvalds 1152*1da177e4SLinus Torvalds i += len; 1153*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 1154*1da177e4SLinus Torvalds return count; 1155*1da177e4SLinus Torvalds } 1156*1da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 1157*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1158*1da177e4SLinus Torvalds if (len < 0) return len; 1159*1da177e4SLinus Torvalds 1160*1da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 1161*1da177e4SLinus Torvalds 1162*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1163*1da177e4SLinus Torvalds return -EFAULT; 1164*1da177e4SLinus Torvalds buf[len] = 0; 1165*1da177e4SLinus Torvalds 1166*1da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 1167*1da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 1168*1da177e4SLinus Torvalds 1169*1da177e4SLinus Torvalds if(debug) 1170*1da177e4SLinus Torvalds printk("pktgen: dst6_max set to: %s\n", buf); 1171*1da177e4SLinus Torvalds 1172*1da177e4SLinus Torvalds i += len; 1173*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 1174*1da177e4SLinus Torvalds return count; 1175*1da177e4SLinus Torvalds } 1176*1da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 1177*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1178*1da177e4SLinus Torvalds if (len < 0) return len; 1179*1da177e4SLinus Torvalds 1180*1da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 1181*1da177e4SLinus Torvalds 1182*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1183*1da177e4SLinus Torvalds return -EFAULT; 1184*1da177e4SLinus Torvalds buf[len] = 0; 1185*1da177e4SLinus Torvalds 1186*1da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); 1187*1da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); 1188*1da177e4SLinus Torvalds 1189*1da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); 1190*1da177e4SLinus Torvalds 1191*1da177e4SLinus Torvalds if(debug) 1192*1da177e4SLinus Torvalds printk("pktgen: src6 set to: %s\n", buf); 1193*1da177e4SLinus Torvalds 1194*1da177e4SLinus Torvalds i += len; 1195*1da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 1196*1da177e4SLinus Torvalds return count; 1197*1da177e4SLinus Torvalds } 1198*1da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 1199*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 1200*1da177e4SLinus Torvalds if (len < 0) { return len; } 1201*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1202*1da177e4SLinus Torvalds return -EFAULT; 1203*1da177e4SLinus Torvalds buf[len] = 0; 1204*1da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 1205*1da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 1206*1da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 1207*1da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 1208*1da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 1209*1da177e4SLinus Torvalds } 1210*1da177e4SLinus Torvalds if(debug) 1211*1da177e4SLinus Torvalds printk("pktgen: src_min set to: %s\n", pkt_dev->src_min); 1212*1da177e4SLinus Torvalds i += len; 1213*1da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 1214*1da177e4SLinus Torvalds return count; 1215*1da177e4SLinus Torvalds } 1216*1da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 1217*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 1218*1da177e4SLinus Torvalds if (len < 0) { return len; } 1219*1da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 1220*1da177e4SLinus Torvalds return -EFAULT; 1221*1da177e4SLinus Torvalds buf[len] = 0; 1222*1da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 1223*1da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 1224*1da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 1225*1da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 1226*1da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 1227*1da177e4SLinus Torvalds } 1228*1da177e4SLinus Torvalds if(debug) 1229*1da177e4SLinus Torvalds printk("pktgen: src_max set to: %s\n", pkt_dev->src_max); 1230*1da177e4SLinus Torvalds i += len; 1231*1da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 1232*1da177e4SLinus Torvalds return count; 1233*1da177e4SLinus Torvalds } 1234*1da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 1235*1da177e4SLinus Torvalds char *v = valstr; 1236*1da177e4SLinus Torvalds unsigned char old_dmac[6]; 1237*1da177e4SLinus Torvalds unsigned char *m = pkt_dev->dst_mac; 1238*1da177e4SLinus Torvalds memcpy(old_dmac, pkt_dev->dst_mac, 6); 1239*1da177e4SLinus Torvalds 1240*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 1241*1da177e4SLinus Torvalds if (len < 0) { return len; } 1242*1da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 1243*1da177e4SLinus Torvalds if( copy_from_user(valstr, &user_buffer[i], len)) 1244*1da177e4SLinus Torvalds return -EFAULT; 1245*1da177e4SLinus Torvalds i += len; 1246*1da177e4SLinus Torvalds 1247*1da177e4SLinus Torvalds for(*m = 0;*v && m < pkt_dev->dst_mac + 6; v++) { 1248*1da177e4SLinus Torvalds if (*v >= '0' && *v <= '9') { 1249*1da177e4SLinus Torvalds *m *= 16; 1250*1da177e4SLinus Torvalds *m += *v - '0'; 1251*1da177e4SLinus Torvalds } 1252*1da177e4SLinus Torvalds if (*v >= 'A' && *v <= 'F') { 1253*1da177e4SLinus Torvalds *m *= 16; 1254*1da177e4SLinus Torvalds *m += *v - 'A' + 10; 1255*1da177e4SLinus Torvalds } 1256*1da177e4SLinus Torvalds if (*v >= 'a' && *v <= 'f') { 1257*1da177e4SLinus Torvalds *m *= 16; 1258*1da177e4SLinus Torvalds *m += *v - 'a' + 10; 1259*1da177e4SLinus Torvalds } 1260*1da177e4SLinus Torvalds if (*v == ':') { 1261*1da177e4SLinus Torvalds m++; 1262*1da177e4SLinus Torvalds *m = 0; 1263*1da177e4SLinus Torvalds } 1264*1da177e4SLinus Torvalds } 1265*1da177e4SLinus Torvalds 1266*1da177e4SLinus Torvalds /* Set up Dest MAC */ 1267*1da177e4SLinus Torvalds if (memcmp(old_dmac, pkt_dev->dst_mac, 6) != 0) 1268*1da177e4SLinus Torvalds memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, 6); 1269*1da177e4SLinus Torvalds 1270*1da177e4SLinus Torvalds sprintf(pg_result, "OK: dstmac"); 1271*1da177e4SLinus Torvalds return count; 1272*1da177e4SLinus Torvalds } 1273*1da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 1274*1da177e4SLinus Torvalds char *v = valstr; 1275*1da177e4SLinus Torvalds unsigned char *m = pkt_dev->src_mac; 1276*1da177e4SLinus Torvalds 1277*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 1278*1da177e4SLinus Torvalds if (len < 0) { return len; } 1279*1da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 1280*1da177e4SLinus Torvalds if( copy_from_user(valstr, &user_buffer[i], len)) 1281*1da177e4SLinus Torvalds return -EFAULT; 1282*1da177e4SLinus Torvalds i += len; 1283*1da177e4SLinus Torvalds 1284*1da177e4SLinus Torvalds for(*m = 0;*v && m < pkt_dev->src_mac + 6; v++) { 1285*1da177e4SLinus Torvalds if (*v >= '0' && *v <= '9') { 1286*1da177e4SLinus Torvalds *m *= 16; 1287*1da177e4SLinus Torvalds *m += *v - '0'; 1288*1da177e4SLinus Torvalds } 1289*1da177e4SLinus Torvalds if (*v >= 'A' && *v <= 'F') { 1290*1da177e4SLinus Torvalds *m *= 16; 1291*1da177e4SLinus Torvalds *m += *v - 'A' + 10; 1292*1da177e4SLinus Torvalds } 1293*1da177e4SLinus Torvalds if (*v >= 'a' && *v <= 'f') { 1294*1da177e4SLinus Torvalds *m *= 16; 1295*1da177e4SLinus Torvalds *m += *v - 'a' + 10; 1296*1da177e4SLinus Torvalds } 1297*1da177e4SLinus Torvalds if (*v == ':') { 1298*1da177e4SLinus Torvalds m++; 1299*1da177e4SLinus Torvalds *m = 0; 1300*1da177e4SLinus Torvalds } 1301*1da177e4SLinus Torvalds } 1302*1da177e4SLinus Torvalds 1303*1da177e4SLinus Torvalds sprintf(pg_result, "OK: srcmac"); 1304*1da177e4SLinus Torvalds return count; 1305*1da177e4SLinus Torvalds } 1306*1da177e4SLinus Torvalds 1307*1da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 1308*1da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 1309*1da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 1310*1da177e4SLinus Torvalds return count; 1311*1da177e4SLinus Torvalds } 1312*1da177e4SLinus Torvalds 1313*1da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 1314*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1315*1da177e4SLinus Torvalds if (len < 0) { return len; } 1316*1da177e4SLinus Torvalds i += len; 1317*1da177e4SLinus Torvalds if (value > MAX_CFLOWS) 1318*1da177e4SLinus Torvalds value = MAX_CFLOWS; 1319*1da177e4SLinus Torvalds 1320*1da177e4SLinus Torvalds pkt_dev->cflows = value; 1321*1da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 1322*1da177e4SLinus Torvalds return count; 1323*1da177e4SLinus Torvalds } 1324*1da177e4SLinus Torvalds 1325*1da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 1326*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1327*1da177e4SLinus Torvalds if (len < 0) { return len; } 1328*1da177e4SLinus Torvalds i += len; 1329*1da177e4SLinus Torvalds pkt_dev->lflow = value; 1330*1da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 1331*1da177e4SLinus Torvalds return count; 1332*1da177e4SLinus Torvalds } 1333*1da177e4SLinus Torvalds 1334*1da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 1335*1da177e4SLinus Torvalds return -EINVAL; 1336*1da177e4SLinus Torvalds } 1337*1da177e4SLinus Torvalds 1338*1da177e4SLinus Torvalds static int proc_thread_read(char *buf , char **start, off_t offset, 1339*1da177e4SLinus Torvalds int len, int *eof, void *data) 1340*1da177e4SLinus Torvalds { 1341*1da177e4SLinus Torvalds char *p; 1342*1da177e4SLinus Torvalds struct pktgen_thread *t = (struct pktgen_thread*)(data); 1343*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 1344*1da177e4SLinus Torvalds 1345*1da177e4SLinus Torvalds 1346*1da177e4SLinus Torvalds if (!t) { 1347*1da177e4SLinus Torvalds printk("pktgen: ERROR: could not find thread in proc_thread_read\n"); 1348*1da177e4SLinus Torvalds return -EINVAL; 1349*1da177e4SLinus Torvalds } 1350*1da177e4SLinus Torvalds 1351*1da177e4SLinus Torvalds p = buf; 1352*1da177e4SLinus Torvalds p += sprintf(p, "Name: %s max_before_softirq: %d\n", 1353*1da177e4SLinus Torvalds t->name, t->max_before_softirq); 1354*1da177e4SLinus Torvalds 1355*1da177e4SLinus Torvalds p += sprintf(p, "Running: "); 1356*1da177e4SLinus Torvalds 1357*1da177e4SLinus Torvalds if_lock(t); 1358*1da177e4SLinus Torvalds for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) 1359*1da177e4SLinus Torvalds if(pkt_dev->running) 1360*1da177e4SLinus Torvalds p += sprintf(p, "%s ", pkt_dev->ifname); 1361*1da177e4SLinus Torvalds 1362*1da177e4SLinus Torvalds p += sprintf(p, "\nStopped: "); 1363*1da177e4SLinus Torvalds 1364*1da177e4SLinus Torvalds for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) 1365*1da177e4SLinus Torvalds if(!pkt_dev->running) 1366*1da177e4SLinus Torvalds p += sprintf(p, "%s ", pkt_dev->ifname); 1367*1da177e4SLinus Torvalds 1368*1da177e4SLinus Torvalds if (t->result[0]) 1369*1da177e4SLinus Torvalds p += sprintf(p, "\nResult: %s\n", t->result); 1370*1da177e4SLinus Torvalds else 1371*1da177e4SLinus Torvalds p += sprintf(p, "\nResult: NA\n"); 1372*1da177e4SLinus Torvalds 1373*1da177e4SLinus Torvalds *eof = 1; 1374*1da177e4SLinus Torvalds 1375*1da177e4SLinus Torvalds if_unlock(t); 1376*1da177e4SLinus Torvalds 1377*1da177e4SLinus Torvalds return p - buf; 1378*1da177e4SLinus Torvalds } 1379*1da177e4SLinus Torvalds 1380*1da177e4SLinus Torvalds static int proc_thread_write(struct file *file, const char __user *user_buffer, 1381*1da177e4SLinus Torvalds unsigned long count, void *data) 1382*1da177e4SLinus Torvalds { 1383*1da177e4SLinus Torvalds int i = 0, max, len, ret; 1384*1da177e4SLinus Torvalds char name[40]; 1385*1da177e4SLinus Torvalds struct pktgen_thread *t; 1386*1da177e4SLinus Torvalds char *pg_result; 1387*1da177e4SLinus Torvalds unsigned long value = 0; 1388*1da177e4SLinus Torvalds 1389*1da177e4SLinus Torvalds if (count < 1) { 1390*1da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 1391*1da177e4SLinus Torvalds return -EINVAL; 1392*1da177e4SLinus Torvalds } 1393*1da177e4SLinus Torvalds 1394*1da177e4SLinus Torvalds max = count - i; 1395*1da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 1396*1da177e4SLinus Torvalds if (len < 0) 1397*1da177e4SLinus Torvalds return len; 1398*1da177e4SLinus Torvalds 1399*1da177e4SLinus Torvalds i += len; 1400*1da177e4SLinus Torvalds 1401*1da177e4SLinus Torvalds /* Read variable name */ 1402*1da177e4SLinus Torvalds 1403*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 1404*1da177e4SLinus Torvalds if (len < 0) 1405*1da177e4SLinus Torvalds return len; 1406*1da177e4SLinus Torvalds 1407*1da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 1408*1da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 1409*1da177e4SLinus Torvalds return -EFAULT; 1410*1da177e4SLinus Torvalds i += len; 1411*1da177e4SLinus Torvalds 1412*1da177e4SLinus Torvalds max = count -i; 1413*1da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 1414*1da177e4SLinus Torvalds if (len < 0) 1415*1da177e4SLinus Torvalds return len; 1416*1da177e4SLinus Torvalds 1417*1da177e4SLinus Torvalds i += len; 1418*1da177e4SLinus Torvalds 1419*1da177e4SLinus Torvalds if (debug) 1420*1da177e4SLinus Torvalds printk("pktgen: t=%s, count=%lu\n", name, count); 1421*1da177e4SLinus Torvalds 1422*1da177e4SLinus Torvalds 1423*1da177e4SLinus Torvalds t = (struct pktgen_thread*)(data); 1424*1da177e4SLinus Torvalds if(!t) { 1425*1da177e4SLinus Torvalds printk("pktgen: ERROR: No thread\n"); 1426*1da177e4SLinus Torvalds ret = -EINVAL; 1427*1da177e4SLinus Torvalds goto out; 1428*1da177e4SLinus Torvalds } 1429*1da177e4SLinus Torvalds 1430*1da177e4SLinus Torvalds pg_result = &(t->result[0]); 1431*1da177e4SLinus Torvalds 1432*1da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 1433*1da177e4SLinus Torvalds char f[32]; 1434*1da177e4SLinus Torvalds memset(f, 0, 32); 1435*1da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 1436*1da177e4SLinus Torvalds if (len < 0) { 1437*1da177e4SLinus Torvalds ret = len; 1438*1da177e4SLinus Torvalds goto out; 1439*1da177e4SLinus Torvalds } 1440*1da177e4SLinus Torvalds if( copy_from_user(f, &user_buffer[i], len) ) 1441*1da177e4SLinus Torvalds return -EFAULT; 1442*1da177e4SLinus Torvalds i += len; 1443*1da177e4SLinus Torvalds thread_lock(); 1444*1da177e4SLinus Torvalds pktgen_add_device(t, f); 1445*1da177e4SLinus Torvalds thread_unlock(); 1446*1da177e4SLinus Torvalds ret = count; 1447*1da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 1448*1da177e4SLinus Torvalds goto out; 1449*1da177e4SLinus Torvalds } 1450*1da177e4SLinus Torvalds 1451*1da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 1452*1da177e4SLinus Torvalds thread_lock(); 1453*1da177e4SLinus Torvalds t->control |= T_REMDEV; 1454*1da177e4SLinus Torvalds thread_unlock(); 1455*1da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 1456*1da177e4SLinus Torvalds schedule_timeout(HZ/8); /* Propagate thread->control */ 1457*1da177e4SLinus Torvalds ret = count; 1458*1da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 1459*1da177e4SLinus Torvalds goto out; 1460*1da177e4SLinus Torvalds } 1461*1da177e4SLinus Torvalds 1462*1da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1463*1da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1464*1da177e4SLinus Torvalds thread_lock(); 1465*1da177e4SLinus Torvalds t->max_before_softirq = value; 1466*1da177e4SLinus Torvalds thread_unlock(); 1467*1da177e4SLinus Torvalds ret = count; 1468*1da177e4SLinus Torvalds sprintf(pg_result, "OK: max_before_softirq=%lu", value); 1469*1da177e4SLinus Torvalds goto out; 1470*1da177e4SLinus Torvalds } 1471*1da177e4SLinus Torvalds 1472*1da177e4SLinus Torvalds ret = -EINVAL; 1473*1da177e4SLinus Torvalds out: 1474*1da177e4SLinus Torvalds 1475*1da177e4SLinus Torvalds return ret; 1476*1da177e4SLinus Torvalds } 1477*1da177e4SLinus Torvalds 1478*1da177e4SLinus Torvalds static int create_proc_dir(void) 1479*1da177e4SLinus Torvalds { 1480*1da177e4SLinus Torvalds int len; 1481*1da177e4SLinus Torvalds /* does proc_dir already exists */ 1482*1da177e4SLinus Torvalds len = strlen(PG_PROC_DIR); 1483*1da177e4SLinus Torvalds 1484*1da177e4SLinus Torvalds for (pg_proc_dir = proc_net->subdir; pg_proc_dir; pg_proc_dir=pg_proc_dir->next) { 1485*1da177e4SLinus Torvalds if ((pg_proc_dir->namelen == len) && 1486*1da177e4SLinus Torvalds (! memcmp(pg_proc_dir->name, PG_PROC_DIR, len))) 1487*1da177e4SLinus Torvalds break; 1488*1da177e4SLinus Torvalds } 1489*1da177e4SLinus Torvalds 1490*1da177e4SLinus Torvalds if (!pg_proc_dir) 1491*1da177e4SLinus Torvalds pg_proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net); 1492*1da177e4SLinus Torvalds 1493*1da177e4SLinus Torvalds if (!pg_proc_dir) 1494*1da177e4SLinus Torvalds return -ENODEV; 1495*1da177e4SLinus Torvalds 1496*1da177e4SLinus Torvalds return 0; 1497*1da177e4SLinus Torvalds } 1498*1da177e4SLinus Torvalds 1499*1da177e4SLinus Torvalds static int remove_proc_dir(void) 1500*1da177e4SLinus Torvalds { 1501*1da177e4SLinus Torvalds remove_proc_entry(PG_PROC_DIR, proc_net); 1502*1da177e4SLinus Torvalds return 0; 1503*1da177e4SLinus Torvalds } 1504*1da177e4SLinus Torvalds 1505*1da177e4SLinus Torvalds /* Think find or remove for NN */ 1506*1da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char* ifname, int remove) 1507*1da177e4SLinus Torvalds { 1508*1da177e4SLinus Torvalds struct pktgen_thread *t; 1509*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 1510*1da177e4SLinus Torvalds 1511*1da177e4SLinus Torvalds t = pktgen_threads; 1512*1da177e4SLinus Torvalds 1513*1da177e4SLinus Torvalds while (t) { 1514*1da177e4SLinus Torvalds pkt_dev = pktgen_find_dev(t, ifname); 1515*1da177e4SLinus Torvalds if (pkt_dev) { 1516*1da177e4SLinus Torvalds if(remove) { 1517*1da177e4SLinus Torvalds if_lock(t); 1518*1da177e4SLinus Torvalds pktgen_remove_device(t, pkt_dev); 1519*1da177e4SLinus Torvalds if_unlock(t); 1520*1da177e4SLinus Torvalds } 1521*1da177e4SLinus Torvalds break; 1522*1da177e4SLinus Torvalds } 1523*1da177e4SLinus Torvalds t = t->next; 1524*1da177e4SLinus Torvalds } 1525*1da177e4SLinus Torvalds return pkt_dev; 1526*1da177e4SLinus Torvalds } 1527*1da177e4SLinus Torvalds 1528*1da177e4SLinus Torvalds static struct pktgen_dev *pktgen_NN_threads(const char* ifname, int remove) 1529*1da177e4SLinus Torvalds { 1530*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 1531*1da177e4SLinus Torvalds thread_lock(); 1532*1da177e4SLinus Torvalds pkt_dev = __pktgen_NN_threads(ifname, remove); 1533*1da177e4SLinus Torvalds thread_unlock(); 1534*1da177e4SLinus Torvalds return pkt_dev; 1535*1da177e4SLinus Torvalds } 1536*1da177e4SLinus Torvalds 1537*1da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *unused, unsigned long event, void *ptr) 1538*1da177e4SLinus Torvalds { 1539*1da177e4SLinus Torvalds struct net_device *dev = (struct net_device *)(ptr); 1540*1da177e4SLinus Torvalds 1541*1da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 1542*1da177e4SLinus Torvalds * as we run under the RTNL lock. 1543*1da177e4SLinus Torvalds */ 1544*1da177e4SLinus Torvalds 1545*1da177e4SLinus Torvalds switch (event) { 1546*1da177e4SLinus Torvalds case NETDEV_CHANGEADDR: 1547*1da177e4SLinus Torvalds case NETDEV_GOING_DOWN: 1548*1da177e4SLinus Torvalds case NETDEV_DOWN: 1549*1da177e4SLinus Torvalds case NETDEV_UP: 1550*1da177e4SLinus Torvalds /* Ignore for now */ 1551*1da177e4SLinus Torvalds break; 1552*1da177e4SLinus Torvalds 1553*1da177e4SLinus Torvalds case NETDEV_UNREGISTER: 1554*1da177e4SLinus Torvalds pktgen_NN_threads(dev->name, REMOVE); 1555*1da177e4SLinus Torvalds break; 1556*1da177e4SLinus Torvalds }; 1557*1da177e4SLinus Torvalds 1558*1da177e4SLinus Torvalds return NOTIFY_DONE; 1559*1da177e4SLinus Torvalds } 1560*1da177e4SLinus Torvalds 1561*1da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 1562*1da177e4SLinus Torvalds 1563*1da177e4SLinus Torvalds static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) { 1564*1da177e4SLinus Torvalds struct net_device *odev; 1565*1da177e4SLinus Torvalds 1566*1da177e4SLinus Torvalds /* Clean old setups */ 1567*1da177e4SLinus Torvalds 1568*1da177e4SLinus Torvalds if (pkt_dev->odev) { 1569*1da177e4SLinus Torvalds dev_put(pkt_dev->odev); 1570*1da177e4SLinus Torvalds pkt_dev->odev = NULL; 1571*1da177e4SLinus Torvalds } 1572*1da177e4SLinus Torvalds 1573*1da177e4SLinus Torvalds odev = dev_get_by_name(pkt_dev->ifname); 1574*1da177e4SLinus Torvalds 1575*1da177e4SLinus Torvalds if (!odev) { 1576*1da177e4SLinus Torvalds printk("pktgen: no such netdevice: \"%s\"\n", pkt_dev->ifname); 1577*1da177e4SLinus Torvalds goto out; 1578*1da177e4SLinus Torvalds } 1579*1da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 1580*1da177e4SLinus Torvalds printk("pktgen: not an ethernet device: \"%s\"\n", pkt_dev->ifname); 1581*1da177e4SLinus Torvalds goto out_put; 1582*1da177e4SLinus Torvalds } 1583*1da177e4SLinus Torvalds if (!netif_running(odev)) { 1584*1da177e4SLinus Torvalds printk("pktgen: device is down: \"%s\"\n", pkt_dev->ifname); 1585*1da177e4SLinus Torvalds goto out_put; 1586*1da177e4SLinus Torvalds } 1587*1da177e4SLinus Torvalds pkt_dev->odev = odev; 1588*1da177e4SLinus Torvalds 1589*1da177e4SLinus Torvalds return pkt_dev->odev; 1590*1da177e4SLinus Torvalds 1591*1da177e4SLinus Torvalds out_put: 1592*1da177e4SLinus Torvalds dev_put(odev); 1593*1da177e4SLinus Torvalds out: 1594*1da177e4SLinus Torvalds return NULL; 1595*1da177e4SLinus Torvalds 1596*1da177e4SLinus Torvalds } 1597*1da177e4SLinus Torvalds 1598*1da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 1599*1da177e4SLinus Torvalds * structure to have the right information to create/send packets 1600*1da177e4SLinus Torvalds */ 1601*1da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 1602*1da177e4SLinus Torvalds { 1603*1da177e4SLinus Torvalds /* Try once more, just in case it works now. */ 1604*1da177e4SLinus Torvalds if (!pkt_dev->odev) 1605*1da177e4SLinus Torvalds pktgen_setup_dev(pkt_dev); 1606*1da177e4SLinus Torvalds 1607*1da177e4SLinus Torvalds if (!pkt_dev->odev) { 1608*1da177e4SLinus Torvalds printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 1609*1da177e4SLinus Torvalds sprintf(pkt_dev->result, "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 1610*1da177e4SLinus Torvalds return; 1611*1da177e4SLinus Torvalds } 1612*1da177e4SLinus Torvalds 1613*1da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 1614*1da177e4SLinus Torvalds 1615*1da177e4SLinus Torvalds if ((pkt_dev->src_mac[0] == 0) && 1616*1da177e4SLinus Torvalds (pkt_dev->src_mac[1] == 0) && 1617*1da177e4SLinus Torvalds (pkt_dev->src_mac[2] == 0) && 1618*1da177e4SLinus Torvalds (pkt_dev->src_mac[3] == 0) && 1619*1da177e4SLinus Torvalds (pkt_dev->src_mac[4] == 0) && 1620*1da177e4SLinus Torvalds (pkt_dev->src_mac[5] == 0)) { 1621*1da177e4SLinus Torvalds 1622*1da177e4SLinus Torvalds memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, 6); 1623*1da177e4SLinus Torvalds } 1624*1da177e4SLinus Torvalds /* Set up Dest MAC */ 1625*1da177e4SLinus Torvalds memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, 6); 1626*1da177e4SLinus Torvalds 1627*1da177e4SLinus Torvalds /* Set up pkt size */ 1628*1da177e4SLinus Torvalds pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 1629*1da177e4SLinus Torvalds 1630*1da177e4SLinus Torvalds if(pkt_dev->flags & F_IPV6) { 1631*1da177e4SLinus Torvalds /* 1632*1da177e4SLinus Torvalds * Skip this automatic address setting until locks or functions 1633*1da177e4SLinus Torvalds * gets exported 1634*1da177e4SLinus Torvalds */ 1635*1da177e4SLinus Torvalds 1636*1da177e4SLinus Torvalds #ifdef NOTNOW 1637*1da177e4SLinus Torvalds int i, set = 0, err=1; 1638*1da177e4SLinus Torvalds struct inet6_dev *idev; 1639*1da177e4SLinus Torvalds 1640*1da177e4SLinus Torvalds for(i=0; i< IN6_ADDR_HSIZE; i++) 1641*1da177e4SLinus Torvalds if(pkt_dev->cur_in6_saddr.s6_addr[i]) { 1642*1da177e4SLinus Torvalds set = 1; 1643*1da177e4SLinus Torvalds break; 1644*1da177e4SLinus Torvalds } 1645*1da177e4SLinus Torvalds 1646*1da177e4SLinus Torvalds if(!set) { 1647*1da177e4SLinus Torvalds 1648*1da177e4SLinus Torvalds /* 1649*1da177e4SLinus Torvalds * Use linklevel address if unconfigured. 1650*1da177e4SLinus Torvalds * 1651*1da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 1652*1da177e4SLinus Torvalds */ 1653*1da177e4SLinus Torvalds 1654*1da177e4SLinus Torvalds 1655*1da177e4SLinus Torvalds read_lock(&addrconf_lock); 1656*1da177e4SLinus Torvalds if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { 1657*1da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 1658*1da177e4SLinus Torvalds 1659*1da177e4SLinus Torvalds read_lock_bh(&idev->lock); 1660*1da177e4SLinus Torvalds for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { 1661*1da177e4SLinus Torvalds if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { 1662*1da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &ifp->addr); 1663*1da177e4SLinus Torvalds err = 0; 1664*1da177e4SLinus Torvalds break; 1665*1da177e4SLinus Torvalds } 1666*1da177e4SLinus Torvalds } 1667*1da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 1668*1da177e4SLinus Torvalds } 1669*1da177e4SLinus Torvalds read_unlock(&addrconf_lock); 1670*1da177e4SLinus Torvalds if(err) printk("pktgen: ERROR: IPv6 link address not availble.\n"); 1671*1da177e4SLinus Torvalds } 1672*1da177e4SLinus Torvalds #endif 1673*1da177e4SLinus Torvalds } 1674*1da177e4SLinus Torvalds else { 1675*1da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 1676*1da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 1677*1da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 1678*1da177e4SLinus Torvalds 1679*1da177e4SLinus Torvalds struct in_device *in_dev; 1680*1da177e4SLinus Torvalds 1681*1da177e4SLinus Torvalds rcu_read_lock(); 1682*1da177e4SLinus Torvalds in_dev = __in_dev_get(pkt_dev->odev); 1683*1da177e4SLinus Torvalds if (in_dev) { 1684*1da177e4SLinus Torvalds if (in_dev->ifa_list) { 1685*1da177e4SLinus Torvalds pkt_dev->saddr_min = in_dev->ifa_list->ifa_address; 1686*1da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 1687*1da177e4SLinus Torvalds } 1688*1da177e4SLinus Torvalds __in_dev_put(in_dev); 1689*1da177e4SLinus Torvalds } 1690*1da177e4SLinus Torvalds rcu_read_unlock(); 1691*1da177e4SLinus Torvalds } 1692*1da177e4SLinus Torvalds else { 1693*1da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 1694*1da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 1695*1da177e4SLinus Torvalds } 1696*1da177e4SLinus Torvalds 1697*1da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 1698*1da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 1699*1da177e4SLinus Torvalds } 1700*1da177e4SLinus Torvalds /* Initialize current values. */ 1701*1da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 1702*1da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 1703*1da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 1704*1da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 1705*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 1706*1da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 1707*1da177e4SLinus Torvalds pkt_dev->nflows = 0; 1708*1da177e4SLinus Torvalds } 1709*1da177e4SLinus Torvalds 1710*1da177e4SLinus Torvalds static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) 1711*1da177e4SLinus Torvalds { 1712*1da177e4SLinus Torvalds __u64 start; 1713*1da177e4SLinus Torvalds __u64 now; 1714*1da177e4SLinus Torvalds 1715*1da177e4SLinus Torvalds start = now = getCurUs(); 1716*1da177e4SLinus Torvalds printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now)); 1717*1da177e4SLinus Torvalds while (now < spin_until_us) { 1718*1da177e4SLinus Torvalds /* TODO: optimise sleeping behavior */ 1719*1da177e4SLinus Torvalds if (spin_until_us - now > (1000000/HZ)+1) { 1720*1da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 1721*1da177e4SLinus Torvalds schedule_timeout(1); 1722*1da177e4SLinus Torvalds } else if (spin_until_us - now > 100) { 1723*1da177e4SLinus Torvalds do_softirq(); 1724*1da177e4SLinus Torvalds if (!pkt_dev->running) 1725*1da177e4SLinus Torvalds return; 1726*1da177e4SLinus Torvalds if (need_resched()) 1727*1da177e4SLinus Torvalds schedule(); 1728*1da177e4SLinus Torvalds } 1729*1da177e4SLinus Torvalds 1730*1da177e4SLinus Torvalds now = getCurUs(); 1731*1da177e4SLinus Torvalds } 1732*1da177e4SLinus Torvalds 1733*1da177e4SLinus Torvalds pkt_dev->idle_acc += now - start; 1734*1da177e4SLinus Torvalds } 1735*1da177e4SLinus Torvalds 1736*1da177e4SLinus Torvalds 1737*1da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 1738*1da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 1739*1da177e4SLinus Torvalds */ 1740*1da177e4SLinus Torvalds static void mod_cur_headers(struct pktgen_dev *pkt_dev) { 1741*1da177e4SLinus Torvalds __u32 imn; 1742*1da177e4SLinus Torvalds __u32 imx; 1743*1da177e4SLinus Torvalds int flow = 0; 1744*1da177e4SLinus Torvalds 1745*1da177e4SLinus Torvalds if(pkt_dev->cflows) { 1746*1da177e4SLinus Torvalds flow = pktgen_random() % pkt_dev->cflows; 1747*1da177e4SLinus Torvalds 1748*1da177e4SLinus Torvalds if (pkt_dev->flows[flow].count > pkt_dev->lflow) 1749*1da177e4SLinus Torvalds pkt_dev->flows[flow].count = 0; 1750*1da177e4SLinus Torvalds } 1751*1da177e4SLinus Torvalds 1752*1da177e4SLinus Torvalds 1753*1da177e4SLinus Torvalds /* Deal with source MAC */ 1754*1da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 1755*1da177e4SLinus Torvalds __u32 mc; 1756*1da177e4SLinus Torvalds __u32 tmp; 1757*1da177e4SLinus Torvalds 1758*1da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 1759*1da177e4SLinus Torvalds mc = pktgen_random() % (pkt_dev->src_mac_count); 1760*1da177e4SLinus Torvalds else { 1761*1da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 1762*1da177e4SLinus Torvalds if (pkt_dev->cur_src_mac_offset > pkt_dev->src_mac_count) 1763*1da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 1764*1da177e4SLinus Torvalds } 1765*1da177e4SLinus Torvalds 1766*1da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 1767*1da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 1768*1da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 1769*1da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 1770*1da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 1771*1da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 1772*1da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 1773*1da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 1774*1da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 1775*1da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 1776*1da177e4SLinus Torvalds } 1777*1da177e4SLinus Torvalds 1778*1da177e4SLinus Torvalds /* Deal with Destination MAC */ 1779*1da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 1780*1da177e4SLinus Torvalds __u32 mc; 1781*1da177e4SLinus Torvalds __u32 tmp; 1782*1da177e4SLinus Torvalds 1783*1da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 1784*1da177e4SLinus Torvalds mc = pktgen_random() % (pkt_dev->dst_mac_count); 1785*1da177e4SLinus Torvalds 1786*1da177e4SLinus Torvalds else { 1787*1da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 1788*1da177e4SLinus Torvalds if (pkt_dev->cur_dst_mac_offset > pkt_dev->dst_mac_count) { 1789*1da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 1790*1da177e4SLinus Torvalds } 1791*1da177e4SLinus Torvalds } 1792*1da177e4SLinus Torvalds 1793*1da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 1794*1da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 1795*1da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 1796*1da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 1797*1da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 1798*1da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 1799*1da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 1800*1da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 1801*1da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 1802*1da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 1803*1da177e4SLinus Torvalds } 1804*1da177e4SLinus Torvalds 1805*1da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 1806*1da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 1807*1da177e4SLinus Torvalds pkt_dev->cur_udp_src = ((pktgen_random() % (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) + pkt_dev->udp_src_min); 1808*1da177e4SLinus Torvalds 1809*1da177e4SLinus Torvalds else { 1810*1da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 1811*1da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 1812*1da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 1813*1da177e4SLinus Torvalds } 1814*1da177e4SLinus Torvalds } 1815*1da177e4SLinus Torvalds 1816*1da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 1817*1da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 1818*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst = ((pktgen_random() % (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) + pkt_dev->udp_dst_min); 1819*1da177e4SLinus Torvalds } 1820*1da177e4SLinus Torvalds else { 1821*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 1822*1da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 1823*1da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 1824*1da177e4SLinus Torvalds } 1825*1da177e4SLinus Torvalds } 1826*1da177e4SLinus Torvalds 1827*1da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 1828*1da177e4SLinus Torvalds 1829*1da177e4SLinus Torvalds if ((imn = ntohl(pkt_dev->saddr_min)) < (imx = ntohl(pkt_dev->saddr_max))) { 1830*1da177e4SLinus Torvalds __u32 t; 1831*1da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 1832*1da177e4SLinus Torvalds t = ((pktgen_random() % (imx - imn)) + imn); 1833*1da177e4SLinus Torvalds else { 1834*1da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 1835*1da177e4SLinus Torvalds t++; 1836*1da177e4SLinus Torvalds if (t > imx) { 1837*1da177e4SLinus Torvalds t = imn; 1838*1da177e4SLinus Torvalds } 1839*1da177e4SLinus Torvalds } 1840*1da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 1841*1da177e4SLinus Torvalds } 1842*1da177e4SLinus Torvalds 1843*1da177e4SLinus Torvalds if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) { 1844*1da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 1845*1da177e4SLinus Torvalds } else { 1846*1da177e4SLinus Torvalds 1847*1da177e4SLinus Torvalds if ((imn = ntohl(pkt_dev->daddr_min)) < (imx = ntohl(pkt_dev->daddr_max))) { 1848*1da177e4SLinus Torvalds __u32 t; 1849*1da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 1850*1da177e4SLinus Torvalds 1851*1da177e4SLinus Torvalds t = ((pktgen_random() % (imx - imn)) + imn); 1852*1da177e4SLinus Torvalds t = htonl(t); 1853*1da177e4SLinus Torvalds 1854*1da177e4SLinus Torvalds while( LOOPBACK(t) || MULTICAST(t) || BADCLASS(t) || ZERONET(t) || LOCAL_MCAST(t) ) { 1855*1da177e4SLinus Torvalds t = ((pktgen_random() % (imx - imn)) + imn); 1856*1da177e4SLinus Torvalds t = htonl(t); 1857*1da177e4SLinus Torvalds } 1858*1da177e4SLinus Torvalds pkt_dev->cur_daddr = t; 1859*1da177e4SLinus Torvalds } 1860*1da177e4SLinus Torvalds 1861*1da177e4SLinus Torvalds else { 1862*1da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 1863*1da177e4SLinus Torvalds t++; 1864*1da177e4SLinus Torvalds if (t > imx) { 1865*1da177e4SLinus Torvalds t = imn; 1866*1da177e4SLinus Torvalds } 1867*1da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 1868*1da177e4SLinus Torvalds } 1869*1da177e4SLinus Torvalds } 1870*1da177e4SLinus Torvalds if(pkt_dev->cflows) { 1871*1da177e4SLinus Torvalds pkt_dev->flows[flow].cur_daddr = pkt_dev->cur_daddr; 1872*1da177e4SLinus Torvalds pkt_dev->nflows++; 1873*1da177e4SLinus Torvalds } 1874*1da177e4SLinus Torvalds } 1875*1da177e4SLinus Torvalds } 1876*1da177e4SLinus Torvalds else /* IPV6 * */ 1877*1da177e4SLinus Torvalds { 1878*1da177e4SLinus Torvalds if(pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && 1879*1da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && 1880*1da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && 1881*1da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[3] == 0); 1882*1da177e4SLinus Torvalds else { 1883*1da177e4SLinus Torvalds int i; 1884*1da177e4SLinus Torvalds 1885*1da177e4SLinus Torvalds /* Only random destinations yet */ 1886*1da177e4SLinus Torvalds 1887*1da177e4SLinus Torvalds for(i=0; i < 4; i++) { 1888*1da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 1889*1da177e4SLinus Torvalds ((pktgen_random() | 1890*1da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 1891*1da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 1892*1da177e4SLinus Torvalds } 1893*1da177e4SLinus Torvalds } 1894*1da177e4SLinus Torvalds } 1895*1da177e4SLinus Torvalds 1896*1da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 1897*1da177e4SLinus Torvalds __u32 t; 1898*1da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 1899*1da177e4SLinus Torvalds t = ((pktgen_random() % (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)) 1900*1da177e4SLinus Torvalds + pkt_dev->min_pkt_size); 1901*1da177e4SLinus Torvalds } 1902*1da177e4SLinus Torvalds else { 1903*1da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 1904*1da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 1905*1da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 1906*1da177e4SLinus Torvalds } 1907*1da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 1908*1da177e4SLinus Torvalds } 1909*1da177e4SLinus Torvalds 1910*1da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 1911*1da177e4SLinus Torvalds } 1912*1da177e4SLinus Torvalds 1913*1da177e4SLinus Torvalds 1914*1da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 1915*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 1916*1da177e4SLinus Torvalds { 1917*1da177e4SLinus Torvalds struct sk_buff *skb = NULL; 1918*1da177e4SLinus Torvalds __u8 *eth; 1919*1da177e4SLinus Torvalds struct udphdr *udph; 1920*1da177e4SLinus Torvalds int datalen, iplen; 1921*1da177e4SLinus Torvalds struct iphdr *iph; 1922*1da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 1923*1da177e4SLinus Torvalds 1924*1da177e4SLinus Torvalds skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC); 1925*1da177e4SLinus Torvalds if (!skb) { 1926*1da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 1927*1da177e4SLinus Torvalds return NULL; 1928*1da177e4SLinus Torvalds } 1929*1da177e4SLinus Torvalds 1930*1da177e4SLinus Torvalds skb_reserve(skb, 16); 1931*1da177e4SLinus Torvalds 1932*1da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 1933*1da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 1934*1da177e4SLinus Torvalds iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); 1935*1da177e4SLinus Torvalds udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); 1936*1da177e4SLinus Torvalds 1937*1da177e4SLinus Torvalds /* Update any of the values, used when we're incrementing various 1938*1da177e4SLinus Torvalds * fields. 1939*1da177e4SLinus Torvalds */ 1940*1da177e4SLinus Torvalds mod_cur_headers(pkt_dev); 1941*1da177e4SLinus Torvalds 1942*1da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 1943*1da177e4SLinus Torvalds *(u16*)ð[12] = __constant_htons(ETH_P_IP); 1944*1da177e4SLinus Torvalds 1945*1da177e4SLinus Torvalds datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ 1946*1da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) 1947*1da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 1948*1da177e4SLinus Torvalds 1949*1da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 1950*1da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 1951*1da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 1952*1da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 1953*1da177e4SLinus Torvalds 1954*1da177e4SLinus Torvalds iph->ihl = 5; 1955*1da177e4SLinus Torvalds iph->version = 4; 1956*1da177e4SLinus Torvalds iph->ttl = 32; 1957*1da177e4SLinus Torvalds iph->tos = 0; 1958*1da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 1959*1da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 1960*1da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 1961*1da177e4SLinus Torvalds iph->frag_off = 0; 1962*1da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 1963*1da177e4SLinus Torvalds iph->tot_len = htons(iplen); 1964*1da177e4SLinus Torvalds iph->check = 0; 1965*1da177e4SLinus Torvalds iph->check = ip_fast_csum((void *) iph, iph->ihl); 1966*1da177e4SLinus Torvalds skb->protocol = __constant_htons(ETH_P_IP); 1967*1da177e4SLinus Torvalds skb->mac.raw = ((u8 *)iph) - 14; 1968*1da177e4SLinus Torvalds skb->dev = odev; 1969*1da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 1970*1da177e4SLinus Torvalds 1971*1da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 1972*1da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 1973*1da177e4SLinus Torvalds else { 1974*1da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 1975*1da177e4SLinus Torvalds int i; 1976*1da177e4SLinus Torvalds 1977*1da177e4SLinus Torvalds pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); 1978*1da177e4SLinus Torvalds 1979*1da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 1980*1da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 1981*1da177e4SLinus Torvalds if (datalen > frags*PAGE_SIZE) { 1982*1da177e4SLinus Torvalds skb_put(skb, datalen-frags*PAGE_SIZE); 1983*1da177e4SLinus Torvalds datalen = frags*PAGE_SIZE; 1984*1da177e4SLinus Torvalds } 1985*1da177e4SLinus Torvalds 1986*1da177e4SLinus Torvalds i = 0; 1987*1da177e4SLinus Torvalds while (datalen > 0) { 1988*1da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 1989*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 1990*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 1991*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 1992*1da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 1993*1da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 1994*1da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 1995*1da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 1996*1da177e4SLinus Torvalds i++; 1997*1da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 1998*1da177e4SLinus Torvalds } 1999*1da177e4SLinus Torvalds 2000*1da177e4SLinus Torvalds while (i < frags) { 2001*1da177e4SLinus Torvalds int rem; 2002*1da177e4SLinus Torvalds 2003*1da177e4SLinus Torvalds if (i == 0) 2004*1da177e4SLinus Torvalds break; 2005*1da177e4SLinus Torvalds 2006*1da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 2007*1da177e4SLinus Torvalds if (rem == 0) 2008*1da177e4SLinus Torvalds break; 2009*1da177e4SLinus Torvalds 2010*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 2011*1da177e4SLinus Torvalds 2012*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1]; 2013*1da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2014*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page; 2015*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size; 2016*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 2017*1da177e4SLinus Torvalds i++; 2018*1da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 2019*1da177e4SLinus Torvalds } 2020*1da177e4SLinus Torvalds } 2021*1da177e4SLinus Torvalds 2022*1da177e4SLinus Torvalds /* Stamp the time, and sequence number, convert them to network byte order */ 2023*1da177e4SLinus Torvalds 2024*1da177e4SLinus Torvalds if (pgh) { 2025*1da177e4SLinus Torvalds struct timeval timestamp; 2026*1da177e4SLinus Torvalds 2027*1da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 2028*1da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 2029*1da177e4SLinus Torvalds 2030*1da177e4SLinus Torvalds do_gettimeofday(×tamp); 2031*1da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 2032*1da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 2033*1da177e4SLinus Torvalds } 2034*1da177e4SLinus Torvalds pkt_dev->seq_num++; 2035*1da177e4SLinus Torvalds 2036*1da177e4SLinus Torvalds return skb; 2037*1da177e4SLinus Torvalds } 2038*1da177e4SLinus Torvalds 2039*1da177e4SLinus Torvalds /* 2040*1da177e4SLinus Torvalds * scan_ip6, fmt_ip taken from dietlibc-0.21 2041*1da177e4SLinus Torvalds * Author Felix von Leitner <felix-dietlibc@fefe.de> 2042*1da177e4SLinus Torvalds * 2043*1da177e4SLinus Torvalds * Slightly modified for kernel. 2044*1da177e4SLinus Torvalds * Should be candidate for net/ipv4/utils.c 2045*1da177e4SLinus Torvalds * --ro 2046*1da177e4SLinus Torvalds */ 2047*1da177e4SLinus Torvalds 2048*1da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s,char ip[16]) 2049*1da177e4SLinus Torvalds { 2050*1da177e4SLinus Torvalds unsigned int i; 2051*1da177e4SLinus Torvalds unsigned int len=0; 2052*1da177e4SLinus Torvalds unsigned long u; 2053*1da177e4SLinus Torvalds char suffix[16]; 2054*1da177e4SLinus Torvalds unsigned int prefixlen=0; 2055*1da177e4SLinus Torvalds unsigned int suffixlen=0; 2056*1da177e4SLinus Torvalds __u32 tmp; 2057*1da177e4SLinus Torvalds 2058*1da177e4SLinus Torvalds for (i=0; i<16; i++) ip[i]=0; 2059*1da177e4SLinus Torvalds 2060*1da177e4SLinus Torvalds for (;;) { 2061*1da177e4SLinus Torvalds if (*s == ':') { 2062*1da177e4SLinus Torvalds len++; 2063*1da177e4SLinus Torvalds if (s[1] == ':') { /* Found "::", skip to part 2 */ 2064*1da177e4SLinus Torvalds s+=2; 2065*1da177e4SLinus Torvalds len++; 2066*1da177e4SLinus Torvalds break; 2067*1da177e4SLinus Torvalds } 2068*1da177e4SLinus Torvalds s++; 2069*1da177e4SLinus Torvalds } 2070*1da177e4SLinus Torvalds { 2071*1da177e4SLinus Torvalds char *tmp; 2072*1da177e4SLinus Torvalds u=simple_strtoul(s,&tmp,16); 2073*1da177e4SLinus Torvalds i=tmp-s; 2074*1da177e4SLinus Torvalds } 2075*1da177e4SLinus Torvalds 2076*1da177e4SLinus Torvalds if (!i) return 0; 2077*1da177e4SLinus Torvalds if (prefixlen==12 && s[i]=='.') { 2078*1da177e4SLinus Torvalds 2079*1da177e4SLinus Torvalds /* the last 4 bytes may be written as IPv4 address */ 2080*1da177e4SLinus Torvalds 2081*1da177e4SLinus Torvalds tmp = in_aton(s); 2082*1da177e4SLinus Torvalds memcpy((struct in_addr*)(ip+12), &tmp, sizeof(tmp)); 2083*1da177e4SLinus Torvalds return i+len; 2084*1da177e4SLinus Torvalds } 2085*1da177e4SLinus Torvalds ip[prefixlen++] = (u >> 8); 2086*1da177e4SLinus Torvalds ip[prefixlen++] = (u & 255); 2087*1da177e4SLinus Torvalds s += i; len += i; 2088*1da177e4SLinus Torvalds if (prefixlen==16) 2089*1da177e4SLinus Torvalds return len; 2090*1da177e4SLinus Torvalds } 2091*1da177e4SLinus Torvalds 2092*1da177e4SLinus Torvalds /* part 2, after "::" */ 2093*1da177e4SLinus Torvalds for (;;) { 2094*1da177e4SLinus Torvalds if (*s == ':') { 2095*1da177e4SLinus Torvalds if (suffixlen==0) 2096*1da177e4SLinus Torvalds break; 2097*1da177e4SLinus Torvalds s++; 2098*1da177e4SLinus Torvalds len++; 2099*1da177e4SLinus Torvalds } else if (suffixlen!=0) 2100*1da177e4SLinus Torvalds break; 2101*1da177e4SLinus Torvalds { 2102*1da177e4SLinus Torvalds char *tmp; 2103*1da177e4SLinus Torvalds u=simple_strtol(s,&tmp,16); 2104*1da177e4SLinus Torvalds i=tmp-s; 2105*1da177e4SLinus Torvalds } 2106*1da177e4SLinus Torvalds if (!i) { 2107*1da177e4SLinus Torvalds if (*s) len--; 2108*1da177e4SLinus Torvalds break; 2109*1da177e4SLinus Torvalds } 2110*1da177e4SLinus Torvalds if (suffixlen+prefixlen<=12 && s[i]=='.') { 2111*1da177e4SLinus Torvalds tmp = in_aton(s); 2112*1da177e4SLinus Torvalds memcpy((struct in_addr*)(suffix+suffixlen), &tmp, sizeof(tmp)); 2113*1da177e4SLinus Torvalds suffixlen+=4; 2114*1da177e4SLinus Torvalds len+=strlen(s); 2115*1da177e4SLinus Torvalds break; 2116*1da177e4SLinus Torvalds } 2117*1da177e4SLinus Torvalds suffix[suffixlen++] = (u >> 8); 2118*1da177e4SLinus Torvalds suffix[suffixlen++] = (u & 255); 2119*1da177e4SLinus Torvalds s += i; len += i; 2120*1da177e4SLinus Torvalds if (prefixlen+suffixlen==16) 2121*1da177e4SLinus Torvalds break; 2122*1da177e4SLinus Torvalds } 2123*1da177e4SLinus Torvalds for (i=0; i<suffixlen; i++) 2124*1da177e4SLinus Torvalds ip[16-suffixlen+i] = suffix[i]; 2125*1da177e4SLinus Torvalds return len; 2126*1da177e4SLinus Torvalds } 2127*1da177e4SLinus Torvalds 2128*1da177e4SLinus Torvalds static char tohex(char hexdigit) { 2129*1da177e4SLinus Torvalds return hexdigit>9?hexdigit+'a'-10:hexdigit+'0'; 2130*1da177e4SLinus Torvalds } 2131*1da177e4SLinus Torvalds 2132*1da177e4SLinus Torvalds static int fmt_xlong(char* s,unsigned int i) { 2133*1da177e4SLinus Torvalds char* bak=s; 2134*1da177e4SLinus Torvalds *s=tohex((i>>12)&0xf); if (s!=bak || *s!='0') ++s; 2135*1da177e4SLinus Torvalds *s=tohex((i>>8)&0xf); if (s!=bak || *s!='0') ++s; 2136*1da177e4SLinus Torvalds *s=tohex((i>>4)&0xf); if (s!=bak || *s!='0') ++s; 2137*1da177e4SLinus Torvalds *s=tohex(i&0xf); 2138*1da177e4SLinus Torvalds return s-bak+1; 2139*1da177e4SLinus Torvalds } 2140*1da177e4SLinus Torvalds 2141*1da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s,const char ip[16]) { 2142*1da177e4SLinus Torvalds unsigned int len; 2143*1da177e4SLinus Torvalds unsigned int i; 2144*1da177e4SLinus Torvalds unsigned int temp; 2145*1da177e4SLinus Torvalds unsigned int compressing; 2146*1da177e4SLinus Torvalds int j; 2147*1da177e4SLinus Torvalds 2148*1da177e4SLinus Torvalds len = 0; compressing = 0; 2149*1da177e4SLinus Torvalds for (j=0; j<16; j+=2) { 2150*1da177e4SLinus Torvalds 2151*1da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX 2152*1da177e4SLinus Torvalds if (j==12 && !memcmp(ip,V4mappedprefix,12)) { 2153*1da177e4SLinus Torvalds inet_ntoa_r(*(struct in_addr*)(ip+12),s); 2154*1da177e4SLinus Torvalds temp=strlen(s); 2155*1da177e4SLinus Torvalds return len+temp; 2156*1da177e4SLinus Torvalds } 2157*1da177e4SLinus Torvalds #endif 2158*1da177e4SLinus Torvalds temp = ((unsigned long) (unsigned char) ip[j] << 8) + 2159*1da177e4SLinus Torvalds (unsigned long) (unsigned char) ip[j+1]; 2160*1da177e4SLinus Torvalds if (temp == 0) { 2161*1da177e4SLinus Torvalds if (!compressing) { 2162*1da177e4SLinus Torvalds compressing=1; 2163*1da177e4SLinus Torvalds if (j==0) { 2164*1da177e4SLinus Torvalds *s++=':'; ++len; 2165*1da177e4SLinus Torvalds } 2166*1da177e4SLinus Torvalds } 2167*1da177e4SLinus Torvalds } else { 2168*1da177e4SLinus Torvalds if (compressing) { 2169*1da177e4SLinus Torvalds compressing=0; 2170*1da177e4SLinus Torvalds *s++=':'; ++len; 2171*1da177e4SLinus Torvalds } 2172*1da177e4SLinus Torvalds i = fmt_xlong(s,temp); len += i; s += i; 2173*1da177e4SLinus Torvalds if (j<14) { 2174*1da177e4SLinus Torvalds *s++ = ':'; 2175*1da177e4SLinus Torvalds ++len; 2176*1da177e4SLinus Torvalds } 2177*1da177e4SLinus Torvalds } 2178*1da177e4SLinus Torvalds } 2179*1da177e4SLinus Torvalds if (compressing) { 2180*1da177e4SLinus Torvalds *s++=':'; ++len; 2181*1da177e4SLinus Torvalds } 2182*1da177e4SLinus Torvalds *s=0; 2183*1da177e4SLinus Torvalds return len; 2184*1da177e4SLinus Torvalds } 2185*1da177e4SLinus Torvalds 2186*1da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 2187*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 2188*1da177e4SLinus Torvalds { 2189*1da177e4SLinus Torvalds struct sk_buff *skb = NULL; 2190*1da177e4SLinus Torvalds __u8 *eth; 2191*1da177e4SLinus Torvalds struct udphdr *udph; 2192*1da177e4SLinus Torvalds int datalen; 2193*1da177e4SLinus Torvalds struct ipv6hdr *iph; 2194*1da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2195*1da177e4SLinus Torvalds 2196*1da177e4SLinus Torvalds skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC); 2197*1da177e4SLinus Torvalds if (!skb) { 2198*1da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 2199*1da177e4SLinus Torvalds return NULL; 2200*1da177e4SLinus Torvalds } 2201*1da177e4SLinus Torvalds 2202*1da177e4SLinus Torvalds skb_reserve(skb, 16); 2203*1da177e4SLinus Torvalds 2204*1da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 2205*1da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2206*1da177e4SLinus Torvalds iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); 2207*1da177e4SLinus Torvalds udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); 2208*1da177e4SLinus Torvalds 2209*1da177e4SLinus Torvalds 2210*1da177e4SLinus Torvalds /* Update any of the values, used when we're incrementing various 2211*1da177e4SLinus Torvalds * fields. 2212*1da177e4SLinus Torvalds */ 2213*1da177e4SLinus Torvalds mod_cur_headers(pkt_dev); 2214*1da177e4SLinus Torvalds 2215*1da177e4SLinus Torvalds 2216*1da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2217*1da177e4SLinus Torvalds *(u16*)ð[12] = __constant_htons(ETH_P_IPV6); 2218*1da177e4SLinus Torvalds 2219*1da177e4SLinus Torvalds 2220*1da177e4SLinus Torvalds datalen = pkt_dev->cur_pkt_size-14- 2221*1da177e4SLinus Torvalds sizeof(struct ipv6hdr)-sizeof(struct udphdr); /* Eth + IPh + UDPh */ 2222*1da177e4SLinus Torvalds 2223*1da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) { 2224*1da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 2225*1da177e4SLinus Torvalds if (net_ratelimit()) 2226*1da177e4SLinus Torvalds printk(KERN_INFO "pktgen: increased datalen to %d\n", datalen); 2227*1da177e4SLinus Torvalds } 2228*1da177e4SLinus Torvalds 2229*1da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 2230*1da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 2231*1da177e4SLinus Torvalds udph->len = htons(datalen + sizeof(struct udphdr)); 2232*1da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 2233*1da177e4SLinus Torvalds 2234*1da177e4SLinus Torvalds *(u32*)iph = __constant_htonl(0x60000000); /* Version + flow */ 2235*1da177e4SLinus Torvalds 2236*1da177e4SLinus Torvalds iph->hop_limit = 32; 2237*1da177e4SLinus Torvalds 2238*1da177e4SLinus Torvalds iph->payload_len = htons(sizeof(struct udphdr) + datalen); 2239*1da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 2240*1da177e4SLinus Torvalds 2241*1da177e4SLinus Torvalds ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); 2242*1da177e4SLinus Torvalds ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); 2243*1da177e4SLinus Torvalds 2244*1da177e4SLinus Torvalds skb->mac.raw = ((u8 *)iph) - 14; 2245*1da177e4SLinus Torvalds skb->protocol = __constant_htons(ETH_P_IPV6); 2246*1da177e4SLinus Torvalds skb->dev = odev; 2247*1da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 2248*1da177e4SLinus Torvalds 2249*1da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 2250*1da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 2251*1da177e4SLinus Torvalds else { 2252*1da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 2253*1da177e4SLinus Torvalds int i; 2254*1da177e4SLinus Torvalds 2255*1da177e4SLinus Torvalds pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); 2256*1da177e4SLinus Torvalds 2257*1da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 2258*1da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 2259*1da177e4SLinus Torvalds if (datalen > frags*PAGE_SIZE) { 2260*1da177e4SLinus Torvalds skb_put(skb, datalen-frags*PAGE_SIZE); 2261*1da177e4SLinus Torvalds datalen = frags*PAGE_SIZE; 2262*1da177e4SLinus Torvalds } 2263*1da177e4SLinus Torvalds 2264*1da177e4SLinus Torvalds i = 0; 2265*1da177e4SLinus Torvalds while (datalen > 0) { 2266*1da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 2267*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 2268*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 2269*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 2270*1da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 2271*1da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 2272*1da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 2273*1da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 2274*1da177e4SLinus Torvalds i++; 2275*1da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 2276*1da177e4SLinus Torvalds } 2277*1da177e4SLinus Torvalds 2278*1da177e4SLinus Torvalds while (i < frags) { 2279*1da177e4SLinus Torvalds int rem; 2280*1da177e4SLinus Torvalds 2281*1da177e4SLinus Torvalds if (i == 0) 2282*1da177e4SLinus Torvalds break; 2283*1da177e4SLinus Torvalds 2284*1da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 2285*1da177e4SLinus Torvalds if (rem == 0) 2286*1da177e4SLinus Torvalds break; 2287*1da177e4SLinus Torvalds 2288*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 2289*1da177e4SLinus Torvalds 2290*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1]; 2291*1da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2292*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page; 2293*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size; 2294*1da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 2295*1da177e4SLinus Torvalds i++; 2296*1da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 2297*1da177e4SLinus Torvalds } 2298*1da177e4SLinus Torvalds } 2299*1da177e4SLinus Torvalds 2300*1da177e4SLinus Torvalds /* Stamp the time, and sequence number, convert them to network byte order */ 2301*1da177e4SLinus Torvalds /* should we update cloned packets too ? */ 2302*1da177e4SLinus Torvalds if (pgh) { 2303*1da177e4SLinus Torvalds struct timeval timestamp; 2304*1da177e4SLinus Torvalds 2305*1da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 2306*1da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 2307*1da177e4SLinus Torvalds 2308*1da177e4SLinus Torvalds do_gettimeofday(×tamp); 2309*1da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 2310*1da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 2311*1da177e4SLinus Torvalds } 2312*1da177e4SLinus Torvalds pkt_dev->seq_num++; 2313*1da177e4SLinus Torvalds 2314*1da177e4SLinus Torvalds return skb; 2315*1da177e4SLinus Torvalds } 2316*1da177e4SLinus Torvalds 2317*1da177e4SLinus Torvalds static inline struct sk_buff *fill_packet(struct net_device *odev, 2318*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 2319*1da177e4SLinus Torvalds { 2320*1da177e4SLinus Torvalds if(pkt_dev->flags & F_IPV6) 2321*1da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 2322*1da177e4SLinus Torvalds else 2323*1da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 2324*1da177e4SLinus Torvalds } 2325*1da177e4SLinus Torvalds 2326*1da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 2327*1da177e4SLinus Torvalds { 2328*1da177e4SLinus Torvalds pkt_dev->seq_num = 1; 2329*1da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 2330*1da177e4SLinus Torvalds pkt_dev->sofar = 0; 2331*1da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 2332*1da177e4SLinus Torvalds pkt_dev->errors = 0; 2333*1da177e4SLinus Torvalds } 2334*1da177e4SLinus Torvalds 2335*1da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 2336*1da177e4SLinus Torvalds 2337*1da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 2338*1da177e4SLinus Torvalds { 2339*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 2340*1da177e4SLinus Torvalds int started = 0; 2341*1da177e4SLinus Torvalds 2342*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: entering pktgen_run. %p\n", t)); 2343*1da177e4SLinus Torvalds 2344*1da177e4SLinus Torvalds if_lock(t); 2345*1da177e4SLinus Torvalds for (pkt_dev = t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) { 2346*1da177e4SLinus Torvalds 2347*1da177e4SLinus Torvalds /* 2348*1da177e4SLinus Torvalds * setup odev and create initial packet. 2349*1da177e4SLinus Torvalds */ 2350*1da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 2351*1da177e4SLinus Torvalds 2352*1da177e4SLinus Torvalds if(pkt_dev->odev) { 2353*1da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 2354*1da177e4SLinus Torvalds pkt_dev->running = 1; /* Cranke yeself! */ 2355*1da177e4SLinus Torvalds pkt_dev->skb = NULL; 2356*1da177e4SLinus Torvalds pkt_dev->started_at = getCurUs(); 2357*1da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */ 2358*1da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 2359*1da177e4SLinus Torvalds 2360*1da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 2361*1da177e4SLinus Torvalds started++; 2362*1da177e4SLinus Torvalds } 2363*1da177e4SLinus Torvalds else 2364*1da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 2365*1da177e4SLinus Torvalds } 2366*1da177e4SLinus Torvalds if_unlock(t); 2367*1da177e4SLinus Torvalds if(started) t->control &= ~(T_STOP); 2368*1da177e4SLinus Torvalds } 2369*1da177e4SLinus Torvalds 2370*1da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void) 2371*1da177e4SLinus Torvalds { 2372*1da177e4SLinus Torvalds struct pktgen_thread *t = pktgen_threads; 2373*1da177e4SLinus Torvalds 2374*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads.\n")); 2375*1da177e4SLinus Torvalds 2376*1da177e4SLinus Torvalds thread_lock(); 2377*1da177e4SLinus Torvalds while(t) { 2378*1da177e4SLinus Torvalds pktgen_stop(t); 2379*1da177e4SLinus Torvalds t = t->next; 2380*1da177e4SLinus Torvalds } 2381*1da177e4SLinus Torvalds thread_unlock(); 2382*1da177e4SLinus Torvalds } 2383*1da177e4SLinus Torvalds 2384*1da177e4SLinus Torvalds static int thread_is_running(struct pktgen_thread *t ) 2385*1da177e4SLinus Torvalds { 2386*1da177e4SLinus Torvalds struct pktgen_dev *next; 2387*1da177e4SLinus Torvalds int res = 0; 2388*1da177e4SLinus Torvalds 2389*1da177e4SLinus Torvalds for(next=t->if_list; next; next=next->next) { 2390*1da177e4SLinus Torvalds if(next->running) { 2391*1da177e4SLinus Torvalds res = 1; 2392*1da177e4SLinus Torvalds break; 2393*1da177e4SLinus Torvalds } 2394*1da177e4SLinus Torvalds } 2395*1da177e4SLinus Torvalds return res; 2396*1da177e4SLinus Torvalds } 2397*1da177e4SLinus Torvalds 2398*1da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t ) 2399*1da177e4SLinus Torvalds { 2400*1da177e4SLinus Torvalds if_lock(t); 2401*1da177e4SLinus Torvalds 2402*1da177e4SLinus Torvalds while(thread_is_running(t)) { 2403*1da177e4SLinus Torvalds 2404*1da177e4SLinus Torvalds if_unlock(t); 2405*1da177e4SLinus Torvalds 2406*1da177e4SLinus Torvalds msleep_interruptible(100); 2407*1da177e4SLinus Torvalds 2408*1da177e4SLinus Torvalds if (signal_pending(current)) 2409*1da177e4SLinus Torvalds goto signal; 2410*1da177e4SLinus Torvalds if_lock(t); 2411*1da177e4SLinus Torvalds } 2412*1da177e4SLinus Torvalds if_unlock(t); 2413*1da177e4SLinus Torvalds return 1; 2414*1da177e4SLinus Torvalds signal: 2415*1da177e4SLinus Torvalds return 0; 2416*1da177e4SLinus Torvalds } 2417*1da177e4SLinus Torvalds 2418*1da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void) 2419*1da177e4SLinus Torvalds { 2420*1da177e4SLinus Torvalds struct pktgen_thread *t = pktgen_threads; 2421*1da177e4SLinus Torvalds int sig = 1; 2422*1da177e4SLinus Torvalds 2423*1da177e4SLinus Torvalds while (t) { 2424*1da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 2425*1da177e4SLinus Torvalds if( sig == 0 ) break; 2426*1da177e4SLinus Torvalds thread_lock(); 2427*1da177e4SLinus Torvalds t=t->next; 2428*1da177e4SLinus Torvalds thread_unlock(); 2429*1da177e4SLinus Torvalds } 2430*1da177e4SLinus Torvalds if(sig == 0) { 2431*1da177e4SLinus Torvalds thread_lock(); 2432*1da177e4SLinus Torvalds while (t) { 2433*1da177e4SLinus Torvalds t->control |= (T_STOP); 2434*1da177e4SLinus Torvalds t=t->next; 2435*1da177e4SLinus Torvalds } 2436*1da177e4SLinus Torvalds thread_unlock(); 2437*1da177e4SLinus Torvalds } 2438*1da177e4SLinus Torvalds return sig; 2439*1da177e4SLinus Torvalds } 2440*1da177e4SLinus Torvalds 2441*1da177e4SLinus Torvalds static void pktgen_run_all_threads(void) 2442*1da177e4SLinus Torvalds { 2443*1da177e4SLinus Torvalds struct pktgen_thread *t = pktgen_threads; 2444*1da177e4SLinus Torvalds 2445*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n")); 2446*1da177e4SLinus Torvalds 2447*1da177e4SLinus Torvalds thread_lock(); 2448*1da177e4SLinus Torvalds 2449*1da177e4SLinus Torvalds while(t) { 2450*1da177e4SLinus Torvalds t->control |= (T_RUN); 2451*1da177e4SLinus Torvalds t = t->next; 2452*1da177e4SLinus Torvalds } 2453*1da177e4SLinus Torvalds thread_unlock(); 2454*1da177e4SLinus Torvalds 2455*1da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 2456*1da177e4SLinus Torvalds schedule_timeout(HZ/8); /* Propagate thread->control */ 2457*1da177e4SLinus Torvalds 2458*1da177e4SLinus Torvalds pktgen_wait_all_threads_run(); 2459*1da177e4SLinus Torvalds } 2460*1da177e4SLinus Torvalds 2461*1da177e4SLinus Torvalds 2462*1da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 2463*1da177e4SLinus Torvalds { 2464*1da177e4SLinus Torvalds __u64 total_us, bps, mbps, pps, idle; 2465*1da177e4SLinus Torvalds char *p = pkt_dev->result; 2466*1da177e4SLinus Torvalds 2467*1da177e4SLinus Torvalds total_us = pkt_dev->stopped_at - pkt_dev->started_at; 2468*1da177e4SLinus Torvalds 2469*1da177e4SLinus Torvalds idle = pkt_dev->idle_acc; 2470*1da177e4SLinus Torvalds 2471*1da177e4SLinus Torvalds p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 2472*1da177e4SLinus Torvalds (unsigned long long) total_us, 2473*1da177e4SLinus Torvalds (unsigned long long)(total_us - idle), 2474*1da177e4SLinus Torvalds (unsigned long long) idle, 2475*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->sofar, 2476*1da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 2477*1da177e4SLinus Torvalds 2478*1da177e4SLinus Torvalds pps = pkt_dev->sofar * USEC_PER_SEC; 2479*1da177e4SLinus Torvalds 2480*1da177e4SLinus Torvalds while ((total_us >> 32) != 0) { 2481*1da177e4SLinus Torvalds pps >>= 1; 2482*1da177e4SLinus Torvalds total_us >>= 1; 2483*1da177e4SLinus Torvalds } 2484*1da177e4SLinus Torvalds 2485*1da177e4SLinus Torvalds do_div(pps, total_us); 2486*1da177e4SLinus Torvalds 2487*1da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 2488*1da177e4SLinus Torvalds 2489*1da177e4SLinus Torvalds mbps = bps; 2490*1da177e4SLinus Torvalds do_div(mbps, 1000000); 2491*1da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 2492*1da177e4SLinus Torvalds (unsigned long long) pps, 2493*1da177e4SLinus Torvalds (unsigned long long) mbps, 2494*1da177e4SLinus Torvalds (unsigned long long) bps, 2495*1da177e4SLinus Torvalds (unsigned long long) pkt_dev->errors); 2496*1da177e4SLinus Torvalds } 2497*1da177e4SLinus Torvalds 2498*1da177e4SLinus Torvalds 2499*1da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 2500*1da177e4SLinus Torvalds 2501*1da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 2502*1da177e4SLinus Torvalds { 2503*1da177e4SLinus Torvalds 2504*1da177e4SLinus Torvalds if (!pkt_dev->running) { 2505*1da177e4SLinus Torvalds printk("pktgen: interface: %s is already stopped\n", pkt_dev->ifname); 2506*1da177e4SLinus Torvalds return -EINVAL; 2507*1da177e4SLinus Torvalds } 2508*1da177e4SLinus Torvalds 2509*1da177e4SLinus Torvalds pkt_dev->stopped_at = getCurUs(); 2510*1da177e4SLinus Torvalds pkt_dev->running = 0; 2511*1da177e4SLinus Torvalds 2512*1da177e4SLinus Torvalds show_results(pkt_dev, skb_shinfo(pkt_dev->skb)->nr_frags); 2513*1da177e4SLinus Torvalds 2514*1da177e4SLinus Torvalds if (pkt_dev->skb) 2515*1da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 2516*1da177e4SLinus Torvalds 2517*1da177e4SLinus Torvalds pkt_dev->skb = NULL; 2518*1da177e4SLinus Torvalds 2519*1da177e4SLinus Torvalds return 0; 2520*1da177e4SLinus Torvalds } 2521*1da177e4SLinus Torvalds 2522*1da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t ) 2523*1da177e4SLinus Torvalds { 2524*1da177e4SLinus Torvalds struct pktgen_dev *next, *best = NULL; 2525*1da177e4SLinus Torvalds 2526*1da177e4SLinus Torvalds if_lock(t); 2527*1da177e4SLinus Torvalds 2528*1da177e4SLinus Torvalds for(next=t->if_list; next ; next=next->next) { 2529*1da177e4SLinus Torvalds if(!next->running) continue; 2530*1da177e4SLinus Torvalds if(best == NULL) best=next; 2531*1da177e4SLinus Torvalds else if ( next->next_tx_us < best->next_tx_us) 2532*1da177e4SLinus Torvalds best = next; 2533*1da177e4SLinus Torvalds } 2534*1da177e4SLinus Torvalds if_unlock(t); 2535*1da177e4SLinus Torvalds return best; 2536*1da177e4SLinus Torvalds } 2537*1da177e4SLinus Torvalds 2538*1da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t) { 2539*1da177e4SLinus Torvalds struct pktgen_dev *next = NULL; 2540*1da177e4SLinus Torvalds 2541*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: entering pktgen_stop.\n")); 2542*1da177e4SLinus Torvalds 2543*1da177e4SLinus Torvalds if_lock(t); 2544*1da177e4SLinus Torvalds 2545*1da177e4SLinus Torvalds for(next=t->if_list; next; next=next->next) 2546*1da177e4SLinus Torvalds pktgen_stop_device(next); 2547*1da177e4SLinus Torvalds 2548*1da177e4SLinus Torvalds if_unlock(t); 2549*1da177e4SLinus Torvalds } 2550*1da177e4SLinus Torvalds 2551*1da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 2552*1da177e4SLinus Torvalds { 2553*1da177e4SLinus Torvalds struct pktgen_dev *cur, *next = NULL; 2554*1da177e4SLinus Torvalds 2555*1da177e4SLinus Torvalds /* Remove all devices, free mem */ 2556*1da177e4SLinus Torvalds 2557*1da177e4SLinus Torvalds if_lock(t); 2558*1da177e4SLinus Torvalds 2559*1da177e4SLinus Torvalds for(cur=t->if_list; cur; cur=next) { 2560*1da177e4SLinus Torvalds next = cur->next; 2561*1da177e4SLinus Torvalds pktgen_remove_device(t, cur); 2562*1da177e4SLinus Torvalds } 2563*1da177e4SLinus Torvalds 2564*1da177e4SLinus Torvalds if_unlock(t); 2565*1da177e4SLinus Torvalds } 2566*1da177e4SLinus Torvalds 2567*1da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 2568*1da177e4SLinus Torvalds { 2569*1da177e4SLinus Torvalds /* Remove from the thread list */ 2570*1da177e4SLinus Torvalds 2571*1da177e4SLinus Torvalds struct pktgen_thread *tmp = pktgen_threads; 2572*1da177e4SLinus Torvalds 2573*1da177e4SLinus Torvalds if (strlen(t->fname)) 2574*1da177e4SLinus Torvalds remove_proc_entry(t->fname, NULL); 2575*1da177e4SLinus Torvalds 2576*1da177e4SLinus Torvalds thread_lock(); 2577*1da177e4SLinus Torvalds 2578*1da177e4SLinus Torvalds if (tmp == t) 2579*1da177e4SLinus Torvalds pktgen_threads = tmp->next; 2580*1da177e4SLinus Torvalds else { 2581*1da177e4SLinus Torvalds while (tmp) { 2582*1da177e4SLinus Torvalds if (tmp->next == t) { 2583*1da177e4SLinus Torvalds tmp->next = t->next; 2584*1da177e4SLinus Torvalds t->next = NULL; 2585*1da177e4SLinus Torvalds break; 2586*1da177e4SLinus Torvalds } 2587*1da177e4SLinus Torvalds tmp = tmp->next; 2588*1da177e4SLinus Torvalds } 2589*1da177e4SLinus Torvalds } 2590*1da177e4SLinus Torvalds thread_unlock(); 2591*1da177e4SLinus Torvalds } 2592*1da177e4SLinus Torvalds 2593*1da177e4SLinus Torvalds static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) 2594*1da177e4SLinus Torvalds { 2595*1da177e4SLinus Torvalds struct net_device *odev = NULL; 2596*1da177e4SLinus Torvalds __u64 idle_start = 0; 2597*1da177e4SLinus Torvalds int ret; 2598*1da177e4SLinus Torvalds 2599*1da177e4SLinus Torvalds odev = pkt_dev->odev; 2600*1da177e4SLinus Torvalds 2601*1da177e4SLinus Torvalds if (pkt_dev->delay_us || pkt_dev->delay_ns) { 2602*1da177e4SLinus Torvalds u64 now; 2603*1da177e4SLinus Torvalds 2604*1da177e4SLinus Torvalds now = getCurUs(); 2605*1da177e4SLinus Torvalds if (now < pkt_dev->next_tx_us) 2606*1da177e4SLinus Torvalds spin(pkt_dev, pkt_dev->next_tx_us); 2607*1da177e4SLinus Torvalds 2608*1da177e4SLinus Torvalds /* This is max DELAY, this has special meaning of 2609*1da177e4SLinus Torvalds * "never transmit" 2610*1da177e4SLinus Torvalds */ 2611*1da177e4SLinus Torvalds if (pkt_dev->delay_us == 0x7FFFFFFF) { 2612*1da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us; 2613*1da177e4SLinus Torvalds pkt_dev->next_tx_ns = pkt_dev->delay_ns; 2614*1da177e4SLinus Torvalds goto out; 2615*1da177e4SLinus Torvalds } 2616*1da177e4SLinus Torvalds } 2617*1da177e4SLinus Torvalds 2618*1da177e4SLinus Torvalds if (netif_queue_stopped(odev) || need_resched()) { 2619*1da177e4SLinus Torvalds idle_start = getCurUs(); 2620*1da177e4SLinus Torvalds 2621*1da177e4SLinus Torvalds if (!netif_running(odev)) { 2622*1da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 2623*1da177e4SLinus Torvalds goto out; 2624*1da177e4SLinus Torvalds } 2625*1da177e4SLinus Torvalds if (need_resched()) 2626*1da177e4SLinus Torvalds schedule(); 2627*1da177e4SLinus Torvalds 2628*1da177e4SLinus Torvalds pkt_dev->idle_acc += getCurUs() - idle_start; 2629*1da177e4SLinus Torvalds 2630*1da177e4SLinus Torvalds if (netif_queue_stopped(odev)) { 2631*1da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); /* TODO */ 2632*1da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 2633*1da177e4SLinus Torvalds goto out; /* Try the next interface */ 2634*1da177e4SLinus Torvalds } 2635*1da177e4SLinus Torvalds } 2636*1da177e4SLinus Torvalds 2637*1da177e4SLinus Torvalds if (pkt_dev->last_ok || !pkt_dev->skb) { 2638*1da177e4SLinus Torvalds if ((++pkt_dev->clone_count >= pkt_dev->clone_skb ) || (!pkt_dev->skb)) { 2639*1da177e4SLinus Torvalds /* build a new pkt */ 2640*1da177e4SLinus Torvalds if (pkt_dev->skb) 2641*1da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 2642*1da177e4SLinus Torvalds 2643*1da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 2644*1da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 2645*1da177e4SLinus Torvalds printk("pktgen: ERROR: couldn't allocate skb in fill_packet.\n"); 2646*1da177e4SLinus Torvalds schedule(); 2647*1da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 2648*1da177e4SLinus Torvalds goto out; 2649*1da177e4SLinus Torvalds } 2650*1da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 2651*1da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 2652*1da177e4SLinus Torvalds } 2653*1da177e4SLinus Torvalds } 2654*1da177e4SLinus Torvalds 2655*1da177e4SLinus Torvalds spin_lock_bh(&odev->xmit_lock); 2656*1da177e4SLinus Torvalds if (!netif_queue_stopped(odev)) { 2657*1da177e4SLinus Torvalds 2658*1da177e4SLinus Torvalds atomic_inc(&(pkt_dev->skb->users)); 2659*1da177e4SLinus Torvalds retry_now: 2660*1da177e4SLinus Torvalds ret = odev->hard_start_xmit(pkt_dev->skb, odev); 2661*1da177e4SLinus Torvalds if (likely(ret == NETDEV_TX_OK)) { 2662*1da177e4SLinus Torvalds pkt_dev->last_ok = 1; 2663*1da177e4SLinus Torvalds pkt_dev->sofar++; 2664*1da177e4SLinus Torvalds pkt_dev->seq_num++; 2665*1da177e4SLinus Torvalds pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; 2666*1da177e4SLinus Torvalds 2667*1da177e4SLinus Torvalds } else if (ret == NETDEV_TX_LOCKED 2668*1da177e4SLinus Torvalds && (odev->features & NETIF_F_LLTX)) { 2669*1da177e4SLinus Torvalds cpu_relax(); 2670*1da177e4SLinus Torvalds goto retry_now; 2671*1da177e4SLinus Torvalds } else { /* Retry it next time */ 2672*1da177e4SLinus Torvalds 2673*1da177e4SLinus Torvalds atomic_dec(&(pkt_dev->skb->users)); 2674*1da177e4SLinus Torvalds 2675*1da177e4SLinus Torvalds if (debug && net_ratelimit()) 2676*1da177e4SLinus Torvalds printk(KERN_INFO "pktgen: Hard xmit error\n"); 2677*1da177e4SLinus Torvalds 2678*1da177e4SLinus Torvalds pkt_dev->errors++; 2679*1da177e4SLinus Torvalds pkt_dev->last_ok = 0; 2680*1da177e4SLinus Torvalds } 2681*1da177e4SLinus Torvalds 2682*1da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); 2683*1da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 2684*1da177e4SLinus Torvalds 2685*1da177e4SLinus Torvalds pkt_dev->next_tx_us += pkt_dev->delay_us; 2686*1da177e4SLinus Torvalds pkt_dev->next_tx_ns += pkt_dev->delay_ns; 2687*1da177e4SLinus Torvalds 2688*1da177e4SLinus Torvalds if (pkt_dev->next_tx_ns > 1000) { 2689*1da177e4SLinus Torvalds pkt_dev->next_tx_us++; 2690*1da177e4SLinus Torvalds pkt_dev->next_tx_ns -= 1000; 2691*1da177e4SLinus Torvalds } 2692*1da177e4SLinus Torvalds } 2693*1da177e4SLinus Torvalds 2694*1da177e4SLinus Torvalds else { /* Retry it next time */ 2695*1da177e4SLinus Torvalds pkt_dev->last_ok = 0; 2696*1da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); /* TODO */ 2697*1da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 2698*1da177e4SLinus Torvalds } 2699*1da177e4SLinus Torvalds 2700*1da177e4SLinus Torvalds spin_unlock_bh(&odev->xmit_lock); 2701*1da177e4SLinus Torvalds 2702*1da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 2703*1da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 2704*1da177e4SLinus Torvalds if (atomic_read(&(pkt_dev->skb->users)) != 1) { 2705*1da177e4SLinus Torvalds idle_start = getCurUs(); 2706*1da177e4SLinus Torvalds while (atomic_read(&(pkt_dev->skb->users)) != 1) { 2707*1da177e4SLinus Torvalds if (signal_pending(current)) { 2708*1da177e4SLinus Torvalds break; 2709*1da177e4SLinus Torvalds } 2710*1da177e4SLinus Torvalds schedule(); 2711*1da177e4SLinus Torvalds } 2712*1da177e4SLinus Torvalds pkt_dev->idle_acc += getCurUs() - idle_start; 2713*1da177e4SLinus Torvalds } 2714*1da177e4SLinus Torvalds 2715*1da177e4SLinus Torvalds /* Done with this */ 2716*1da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 2717*1da177e4SLinus Torvalds } 2718*1da177e4SLinus Torvalds out:; 2719*1da177e4SLinus Torvalds } 2720*1da177e4SLinus Torvalds 2721*1da177e4SLinus Torvalds /* 2722*1da177e4SLinus Torvalds * Main loop of the thread goes here 2723*1da177e4SLinus Torvalds */ 2724*1da177e4SLinus Torvalds 2725*1da177e4SLinus Torvalds static void pktgen_thread_worker(struct pktgen_thread *t) 2726*1da177e4SLinus Torvalds { 2727*1da177e4SLinus Torvalds DEFINE_WAIT(wait); 2728*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 2729*1da177e4SLinus Torvalds int cpu = t->cpu; 2730*1da177e4SLinus Torvalds sigset_t tmpsig; 2731*1da177e4SLinus Torvalds u32 max_before_softirq; 2732*1da177e4SLinus Torvalds u32 tx_since_softirq = 0; 2733*1da177e4SLinus Torvalds 2734*1da177e4SLinus Torvalds daemonize("pktgen/%d", cpu); 2735*1da177e4SLinus Torvalds 2736*1da177e4SLinus Torvalds /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */ 2737*1da177e4SLinus Torvalds 2738*1da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 2739*1da177e4SLinus Torvalds tmpsig = current->blocked; 2740*1da177e4SLinus Torvalds siginitsetinv(¤t->blocked, 2741*1da177e4SLinus Torvalds sigmask(SIGKILL) | 2742*1da177e4SLinus Torvalds sigmask(SIGSTOP)| 2743*1da177e4SLinus Torvalds sigmask(SIGTERM)); 2744*1da177e4SLinus Torvalds 2745*1da177e4SLinus Torvalds recalc_sigpending(); 2746*1da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 2747*1da177e4SLinus Torvalds 2748*1da177e4SLinus Torvalds /* Migrate to the right CPU */ 2749*1da177e4SLinus Torvalds set_cpus_allowed(current, cpumask_of_cpu(cpu)); 2750*1da177e4SLinus Torvalds if (smp_processor_id() != cpu) 2751*1da177e4SLinus Torvalds BUG(); 2752*1da177e4SLinus Torvalds 2753*1da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 2754*1da177e4SLinus Torvalds 2755*1da177e4SLinus Torvalds t->control &= ~(T_TERMINATE); 2756*1da177e4SLinus Torvalds t->control &= ~(T_RUN); 2757*1da177e4SLinus Torvalds t->control &= ~(T_STOP); 2758*1da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 2759*1da177e4SLinus Torvalds 2760*1da177e4SLinus Torvalds t->pid = current->pid; 2761*1da177e4SLinus Torvalds 2762*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid)); 2763*1da177e4SLinus Torvalds 2764*1da177e4SLinus Torvalds max_before_softirq = t->max_before_softirq; 2765*1da177e4SLinus Torvalds 2766*1da177e4SLinus Torvalds __set_current_state(TASK_INTERRUPTIBLE); 2767*1da177e4SLinus Torvalds mb(); 2768*1da177e4SLinus Torvalds 2769*1da177e4SLinus Torvalds while (1) { 2770*1da177e4SLinus Torvalds 2771*1da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 2772*1da177e4SLinus Torvalds 2773*1da177e4SLinus Torvalds /* 2774*1da177e4SLinus Torvalds * Get next dev to xmit -- if any. 2775*1da177e4SLinus Torvalds */ 2776*1da177e4SLinus Torvalds 2777*1da177e4SLinus Torvalds pkt_dev = next_to_run(t); 2778*1da177e4SLinus Torvalds 2779*1da177e4SLinus Torvalds if (pkt_dev) { 2780*1da177e4SLinus Torvalds 2781*1da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 2782*1da177e4SLinus Torvalds 2783*1da177e4SLinus Torvalds /* 2784*1da177e4SLinus Torvalds * We like to stay RUNNING but must also give 2785*1da177e4SLinus Torvalds * others fair share. 2786*1da177e4SLinus Torvalds */ 2787*1da177e4SLinus Torvalds 2788*1da177e4SLinus Torvalds tx_since_softirq += pkt_dev->last_ok; 2789*1da177e4SLinus Torvalds 2790*1da177e4SLinus Torvalds if (tx_since_softirq > max_before_softirq) { 2791*1da177e4SLinus Torvalds if (local_softirq_pending()) 2792*1da177e4SLinus Torvalds do_softirq(); 2793*1da177e4SLinus Torvalds tx_since_softirq = 0; 2794*1da177e4SLinus Torvalds } 2795*1da177e4SLinus Torvalds } else { 2796*1da177e4SLinus Torvalds prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE); 2797*1da177e4SLinus Torvalds schedule_timeout(HZ/10); 2798*1da177e4SLinus Torvalds finish_wait(&(t->queue), &wait); 2799*1da177e4SLinus Torvalds } 2800*1da177e4SLinus Torvalds 2801*1da177e4SLinus Torvalds /* 2802*1da177e4SLinus Torvalds * Back from sleep, either due to the timeout or signal. 2803*1da177e4SLinus Torvalds * We check if we have any "posted" work for us. 2804*1da177e4SLinus Torvalds */ 2805*1da177e4SLinus Torvalds 2806*1da177e4SLinus Torvalds if (t->control & T_TERMINATE || signal_pending(current)) 2807*1da177e4SLinus Torvalds /* we received a request to terminate ourself */ 2808*1da177e4SLinus Torvalds break; 2809*1da177e4SLinus Torvalds 2810*1da177e4SLinus Torvalds 2811*1da177e4SLinus Torvalds if(t->control & T_STOP) { 2812*1da177e4SLinus Torvalds pktgen_stop(t); 2813*1da177e4SLinus Torvalds t->control &= ~(T_STOP); 2814*1da177e4SLinus Torvalds } 2815*1da177e4SLinus Torvalds 2816*1da177e4SLinus Torvalds if(t->control & T_RUN) { 2817*1da177e4SLinus Torvalds pktgen_run(t); 2818*1da177e4SLinus Torvalds t->control &= ~(T_RUN); 2819*1da177e4SLinus Torvalds } 2820*1da177e4SLinus Torvalds 2821*1da177e4SLinus Torvalds if(t->control & T_REMDEV) { 2822*1da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 2823*1da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 2824*1da177e4SLinus Torvalds } 2825*1da177e4SLinus Torvalds 2826*1da177e4SLinus Torvalds if (need_resched()) 2827*1da177e4SLinus Torvalds schedule(); 2828*1da177e4SLinus Torvalds } 2829*1da177e4SLinus Torvalds 2830*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name)); 2831*1da177e4SLinus Torvalds pktgen_stop(t); 2832*1da177e4SLinus Torvalds 2833*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: %s removing all device\n", t->name)); 2834*1da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 2835*1da177e4SLinus Torvalds 2836*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name)); 2837*1da177e4SLinus Torvalds pktgen_rem_thread(t); 2838*1da177e4SLinus Torvalds } 2839*1da177e4SLinus Torvalds 2840*1da177e4SLinus Torvalds static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char* ifname) 2841*1da177e4SLinus Torvalds { 2842*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 2843*1da177e4SLinus Torvalds if_lock(t); 2844*1da177e4SLinus Torvalds 2845*1da177e4SLinus Torvalds for(pkt_dev=t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) { 2846*1da177e4SLinus Torvalds if (strcmp(pkt_dev->ifname, ifname) == 0) { 2847*1da177e4SLinus Torvalds break; 2848*1da177e4SLinus Torvalds } 2849*1da177e4SLinus Torvalds } 2850*1da177e4SLinus Torvalds 2851*1da177e4SLinus Torvalds if_unlock(t); 2852*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname,pkt_dev)); 2853*1da177e4SLinus Torvalds return pkt_dev; 2854*1da177e4SLinus Torvalds } 2855*1da177e4SLinus Torvalds 2856*1da177e4SLinus Torvalds /* 2857*1da177e4SLinus Torvalds * Adds a dev at front of if_list. 2858*1da177e4SLinus Torvalds */ 2859*1da177e4SLinus Torvalds 2860*1da177e4SLinus Torvalds static int add_dev_to_thread(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) 2861*1da177e4SLinus Torvalds { 2862*1da177e4SLinus Torvalds int rv = 0; 2863*1da177e4SLinus Torvalds 2864*1da177e4SLinus Torvalds if_lock(t); 2865*1da177e4SLinus Torvalds 2866*1da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 2867*1da177e4SLinus Torvalds printk("pktgen: ERROR: already assigned to a thread.\n"); 2868*1da177e4SLinus Torvalds rv = -EBUSY; 2869*1da177e4SLinus Torvalds goto out; 2870*1da177e4SLinus Torvalds } 2871*1da177e4SLinus Torvalds pkt_dev->next =t->if_list; t->if_list=pkt_dev; 2872*1da177e4SLinus Torvalds pkt_dev->pg_thread = t; 2873*1da177e4SLinus Torvalds pkt_dev->running = 0; 2874*1da177e4SLinus Torvalds 2875*1da177e4SLinus Torvalds out: 2876*1da177e4SLinus Torvalds if_unlock(t); 2877*1da177e4SLinus Torvalds return rv; 2878*1da177e4SLinus Torvalds } 2879*1da177e4SLinus Torvalds 2880*1da177e4SLinus Torvalds /* Called under thread lock */ 2881*1da177e4SLinus Torvalds 2882*1da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) 2883*1da177e4SLinus Torvalds { 2884*1da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 2885*1da177e4SLinus Torvalds 2886*1da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 2887*1da177e4SLinus Torvalds 2888*1da177e4SLinus Torvalds if( (pkt_dev = __pktgen_NN_threads(ifname, FIND)) == NULL) { 2889*1da177e4SLinus Torvalds 2890*1da177e4SLinus Torvalds pkt_dev = kmalloc(sizeof(struct pktgen_dev), GFP_KERNEL); 2891*1da177e4SLinus Torvalds if (!pkt_dev) 2892*1da177e4SLinus Torvalds return -ENOMEM; 2893*1da177e4SLinus Torvalds 2894*1da177e4SLinus Torvalds memset(pkt_dev, 0, sizeof(struct pktgen_dev)); 2895*1da177e4SLinus Torvalds 2896*1da177e4SLinus Torvalds pkt_dev->flows = vmalloc(MAX_CFLOWS*sizeof(struct flow_state)); 2897*1da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 2898*1da177e4SLinus Torvalds kfree(pkt_dev); 2899*1da177e4SLinus Torvalds return -ENOMEM; 2900*1da177e4SLinus Torvalds } 2901*1da177e4SLinus Torvalds memset(pkt_dev->flows, 0, MAX_CFLOWS*sizeof(struct flow_state)); 2902*1da177e4SLinus Torvalds 2903*1da177e4SLinus Torvalds pkt_dev->min_pkt_size = ETH_ZLEN; 2904*1da177e4SLinus Torvalds pkt_dev->max_pkt_size = ETH_ZLEN; 2905*1da177e4SLinus Torvalds pkt_dev->nfrags = 0; 2906*1da177e4SLinus Torvalds pkt_dev->clone_skb = pg_clone_skb_d; 2907*1da177e4SLinus Torvalds pkt_dev->delay_us = pg_delay_d / 1000; 2908*1da177e4SLinus Torvalds pkt_dev->delay_ns = pg_delay_d % 1000; 2909*1da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 2910*1da177e4SLinus Torvalds pkt_dev->sofar = 0; 2911*1da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 2912*1da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 2913*1da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 2914*1da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 2915*1da177e4SLinus Torvalds 2916*1da177e4SLinus Torvalds strncpy(pkt_dev->ifname, ifname, 31); 2917*1da177e4SLinus Torvalds sprintf(pkt_dev->fname, "net/%s/%s", PG_PROC_DIR, ifname); 2918*1da177e4SLinus Torvalds 2919*1da177e4SLinus Torvalds if (! pktgen_setup_dev(pkt_dev)) { 2920*1da177e4SLinus Torvalds printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); 2921*1da177e4SLinus Torvalds if (pkt_dev->flows) 2922*1da177e4SLinus Torvalds vfree(pkt_dev->flows); 2923*1da177e4SLinus Torvalds kfree(pkt_dev); 2924*1da177e4SLinus Torvalds return -ENODEV; 2925*1da177e4SLinus Torvalds } 2926*1da177e4SLinus Torvalds 2927*1da177e4SLinus Torvalds pkt_dev->proc_ent = create_proc_entry(pkt_dev->fname, 0600, NULL); 2928*1da177e4SLinus Torvalds if (!pkt_dev->proc_ent) { 2929*1da177e4SLinus Torvalds printk("pktgen: cannot create %s procfs entry.\n", pkt_dev->fname); 2930*1da177e4SLinus Torvalds if (pkt_dev->flows) 2931*1da177e4SLinus Torvalds vfree(pkt_dev->flows); 2932*1da177e4SLinus Torvalds kfree(pkt_dev); 2933*1da177e4SLinus Torvalds return -EINVAL; 2934*1da177e4SLinus Torvalds } 2935*1da177e4SLinus Torvalds pkt_dev->proc_ent->read_proc = proc_if_read; 2936*1da177e4SLinus Torvalds pkt_dev->proc_ent->write_proc = proc_if_write; 2937*1da177e4SLinus Torvalds pkt_dev->proc_ent->data = (void*)(pkt_dev); 2938*1da177e4SLinus Torvalds pkt_dev->proc_ent->owner = THIS_MODULE; 2939*1da177e4SLinus Torvalds 2940*1da177e4SLinus Torvalds return add_dev_to_thread(t, pkt_dev); 2941*1da177e4SLinus Torvalds } 2942*1da177e4SLinus Torvalds else { 2943*1da177e4SLinus Torvalds printk("pktgen: ERROR: interface already used.\n"); 2944*1da177e4SLinus Torvalds return -EBUSY; 2945*1da177e4SLinus Torvalds } 2946*1da177e4SLinus Torvalds } 2947*1da177e4SLinus Torvalds 2948*1da177e4SLinus Torvalds static struct pktgen_thread *pktgen_find_thread(const char* name) 2949*1da177e4SLinus Torvalds { 2950*1da177e4SLinus Torvalds struct pktgen_thread *t = NULL; 2951*1da177e4SLinus Torvalds 2952*1da177e4SLinus Torvalds thread_lock(); 2953*1da177e4SLinus Torvalds 2954*1da177e4SLinus Torvalds t = pktgen_threads; 2955*1da177e4SLinus Torvalds while (t) { 2956*1da177e4SLinus Torvalds if (strcmp(t->name, name) == 0) 2957*1da177e4SLinus Torvalds break; 2958*1da177e4SLinus Torvalds 2959*1da177e4SLinus Torvalds t = t->next; 2960*1da177e4SLinus Torvalds } 2961*1da177e4SLinus Torvalds thread_unlock(); 2962*1da177e4SLinus Torvalds return t; 2963*1da177e4SLinus Torvalds } 2964*1da177e4SLinus Torvalds 2965*1da177e4SLinus Torvalds static int pktgen_create_thread(const char* name, int cpu) 2966*1da177e4SLinus Torvalds { 2967*1da177e4SLinus Torvalds struct pktgen_thread *t = NULL; 2968*1da177e4SLinus Torvalds 2969*1da177e4SLinus Torvalds if (strlen(name) > 31) { 2970*1da177e4SLinus Torvalds printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n"); 2971*1da177e4SLinus Torvalds return -EINVAL; 2972*1da177e4SLinus Torvalds } 2973*1da177e4SLinus Torvalds 2974*1da177e4SLinus Torvalds if (pktgen_find_thread(name)) { 2975*1da177e4SLinus Torvalds printk("pktgen: ERROR: thread: %s already exists\n", name); 2976*1da177e4SLinus Torvalds return -EINVAL; 2977*1da177e4SLinus Torvalds } 2978*1da177e4SLinus Torvalds 2979*1da177e4SLinus Torvalds t = (struct pktgen_thread*)(kmalloc(sizeof(struct pktgen_thread), GFP_KERNEL)); 2980*1da177e4SLinus Torvalds if (!t) { 2981*1da177e4SLinus Torvalds printk("pktgen: ERROR: out of memory, can't create new thread.\n"); 2982*1da177e4SLinus Torvalds return -ENOMEM; 2983*1da177e4SLinus Torvalds } 2984*1da177e4SLinus Torvalds 2985*1da177e4SLinus Torvalds memset(t, 0, sizeof(struct pktgen_thread)); 2986*1da177e4SLinus Torvalds strcpy(t->name, name); 2987*1da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 2988*1da177e4SLinus Torvalds t->cpu = cpu; 2989*1da177e4SLinus Torvalds 2990*1da177e4SLinus Torvalds sprintf(t->fname, "net/%s/%s", PG_PROC_DIR, t->name); 2991*1da177e4SLinus Torvalds t->proc_ent = create_proc_entry(t->fname, 0600, NULL); 2992*1da177e4SLinus Torvalds if (!t->proc_ent) { 2993*1da177e4SLinus Torvalds printk("pktgen: cannot create %s procfs entry.\n", t->fname); 2994*1da177e4SLinus Torvalds kfree(t); 2995*1da177e4SLinus Torvalds return -EINVAL; 2996*1da177e4SLinus Torvalds } 2997*1da177e4SLinus Torvalds t->proc_ent->read_proc = proc_thread_read; 2998*1da177e4SLinus Torvalds t->proc_ent->write_proc = proc_thread_write; 2999*1da177e4SLinus Torvalds t->proc_ent->data = (void*)(t); 3000*1da177e4SLinus Torvalds t->proc_ent->owner = THIS_MODULE; 3001*1da177e4SLinus Torvalds 3002*1da177e4SLinus Torvalds t->next = pktgen_threads; 3003*1da177e4SLinus Torvalds pktgen_threads = t; 3004*1da177e4SLinus Torvalds 3005*1da177e4SLinus Torvalds if (kernel_thread((void *) pktgen_thread_worker, (void *) t, 3006*1da177e4SLinus Torvalds CLONE_FS | CLONE_FILES | CLONE_SIGHAND) < 0) 3007*1da177e4SLinus Torvalds printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu); 3008*1da177e4SLinus Torvalds 3009*1da177e4SLinus Torvalds return 0; 3010*1da177e4SLinus Torvalds } 3011*1da177e4SLinus Torvalds 3012*1da177e4SLinus Torvalds /* 3013*1da177e4SLinus Torvalds * Removes a device from the thread if_list. 3014*1da177e4SLinus Torvalds */ 3015*1da177e4SLinus Torvalds static void _rem_dev_from_if_list(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) 3016*1da177e4SLinus Torvalds { 3017*1da177e4SLinus Torvalds struct pktgen_dev *i, *prev = NULL; 3018*1da177e4SLinus Torvalds 3019*1da177e4SLinus Torvalds i = t->if_list; 3020*1da177e4SLinus Torvalds 3021*1da177e4SLinus Torvalds while(i) { 3022*1da177e4SLinus Torvalds if(i == pkt_dev) { 3023*1da177e4SLinus Torvalds if(prev) prev->next = i->next; 3024*1da177e4SLinus Torvalds else t->if_list = NULL; 3025*1da177e4SLinus Torvalds break; 3026*1da177e4SLinus Torvalds } 3027*1da177e4SLinus Torvalds prev = i; 3028*1da177e4SLinus Torvalds i=i->next; 3029*1da177e4SLinus Torvalds } 3030*1da177e4SLinus Torvalds } 3031*1da177e4SLinus Torvalds 3032*1da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) 3033*1da177e4SLinus Torvalds { 3034*1da177e4SLinus Torvalds 3035*1da177e4SLinus Torvalds PG_DEBUG(printk("pktgen: remove_device pkt_dev=%p\n", pkt_dev)); 3036*1da177e4SLinus Torvalds 3037*1da177e4SLinus Torvalds if (pkt_dev->running) { 3038*1da177e4SLinus Torvalds printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n"); 3039*1da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 3040*1da177e4SLinus Torvalds } 3041*1da177e4SLinus Torvalds 3042*1da177e4SLinus Torvalds /* Dis-associate from the interface */ 3043*1da177e4SLinus Torvalds 3044*1da177e4SLinus Torvalds if (pkt_dev->odev) { 3045*1da177e4SLinus Torvalds dev_put(pkt_dev->odev); 3046*1da177e4SLinus Torvalds pkt_dev->odev = NULL; 3047*1da177e4SLinus Torvalds } 3048*1da177e4SLinus Torvalds 3049*1da177e4SLinus Torvalds /* And update the thread if_list */ 3050*1da177e4SLinus Torvalds 3051*1da177e4SLinus Torvalds _rem_dev_from_if_list(t, pkt_dev); 3052*1da177e4SLinus Torvalds 3053*1da177e4SLinus Torvalds /* Clean up proc file system */ 3054*1da177e4SLinus Torvalds 3055*1da177e4SLinus Torvalds if (strlen(pkt_dev->fname)) 3056*1da177e4SLinus Torvalds remove_proc_entry(pkt_dev->fname, NULL); 3057*1da177e4SLinus Torvalds 3058*1da177e4SLinus Torvalds if (pkt_dev->flows) 3059*1da177e4SLinus Torvalds vfree(pkt_dev->flows); 3060*1da177e4SLinus Torvalds kfree(pkt_dev); 3061*1da177e4SLinus Torvalds return 0; 3062*1da177e4SLinus Torvalds } 3063*1da177e4SLinus Torvalds 3064*1da177e4SLinus Torvalds static int __init pg_init(void) 3065*1da177e4SLinus Torvalds { 3066*1da177e4SLinus Torvalds int cpu; 3067*1da177e4SLinus Torvalds printk(version); 3068*1da177e4SLinus Torvalds 3069*1da177e4SLinus Torvalds module_fname[0] = 0; 3070*1da177e4SLinus Torvalds 3071*1da177e4SLinus Torvalds create_proc_dir(); 3072*1da177e4SLinus Torvalds 3073*1da177e4SLinus Torvalds sprintf(module_fname, "net/%s/pgctrl", PG_PROC_DIR); 3074*1da177e4SLinus Torvalds module_proc_ent = create_proc_entry(module_fname, 0600, NULL); 3075*1da177e4SLinus Torvalds if (!module_proc_ent) { 3076*1da177e4SLinus Torvalds printk("pktgen: ERROR: cannot create %s procfs entry.\n", module_fname); 3077*1da177e4SLinus Torvalds return -EINVAL; 3078*1da177e4SLinus Torvalds } 3079*1da177e4SLinus Torvalds 3080*1da177e4SLinus Torvalds module_proc_ent->proc_fops = &pktgen_fops; 3081*1da177e4SLinus Torvalds module_proc_ent->data = NULL; 3082*1da177e4SLinus Torvalds 3083*1da177e4SLinus Torvalds /* Register us to receive netdevice events */ 3084*1da177e4SLinus Torvalds register_netdevice_notifier(&pktgen_notifier_block); 3085*1da177e4SLinus Torvalds 3086*1da177e4SLinus Torvalds for (cpu = 0; cpu < NR_CPUS ; cpu++) { 3087*1da177e4SLinus Torvalds char buf[30]; 3088*1da177e4SLinus Torvalds 3089*1da177e4SLinus Torvalds if (!cpu_online(cpu)) 3090*1da177e4SLinus Torvalds continue; 3091*1da177e4SLinus Torvalds 3092*1da177e4SLinus Torvalds sprintf(buf, "kpktgend_%i", cpu); 3093*1da177e4SLinus Torvalds pktgen_create_thread(buf, cpu); 3094*1da177e4SLinus Torvalds } 3095*1da177e4SLinus Torvalds return 0; 3096*1da177e4SLinus Torvalds } 3097*1da177e4SLinus Torvalds 3098*1da177e4SLinus Torvalds static void __exit pg_cleanup(void) 3099*1da177e4SLinus Torvalds { 3100*1da177e4SLinus Torvalds wait_queue_head_t queue; 3101*1da177e4SLinus Torvalds init_waitqueue_head(&queue); 3102*1da177e4SLinus Torvalds 3103*1da177e4SLinus Torvalds /* Stop all interfaces & threads */ 3104*1da177e4SLinus Torvalds 3105*1da177e4SLinus Torvalds while (pktgen_threads) { 3106*1da177e4SLinus Torvalds struct pktgen_thread *t = pktgen_threads; 3107*1da177e4SLinus Torvalds pktgen_threads->control |= (T_TERMINATE); 3108*1da177e4SLinus Torvalds 3109*1da177e4SLinus Torvalds wait_event_interruptible_timeout(queue, (t != pktgen_threads), HZ); 3110*1da177e4SLinus Torvalds } 3111*1da177e4SLinus Torvalds 3112*1da177e4SLinus Torvalds /* Un-register us from receiving netdevice events */ 3113*1da177e4SLinus Torvalds unregister_netdevice_notifier(&pktgen_notifier_block); 3114*1da177e4SLinus Torvalds 3115*1da177e4SLinus Torvalds /* Clean up proc file system */ 3116*1da177e4SLinus Torvalds 3117*1da177e4SLinus Torvalds remove_proc_entry(module_fname, NULL); 3118*1da177e4SLinus Torvalds 3119*1da177e4SLinus Torvalds remove_proc_dir(); 3120*1da177e4SLinus Torvalds } 3121*1da177e4SLinus Torvalds 3122*1da177e4SLinus Torvalds 3123*1da177e4SLinus Torvalds module_init(pg_init); 3124*1da177e4SLinus Torvalds module_exit(pg_cleanup); 3125*1da177e4SLinus Torvalds 3126*1da177e4SLinus Torvalds MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se"); 3127*1da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 3128*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3129*1da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3130*1da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3131*1da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3132*1da177e4SLinus Torvalds module_param(debug, int, 0); 3133