11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Authors: 31da177e4SLinus Torvalds * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> 41da177e4SLinus Torvalds * Uppsala University and 51da177e4SLinus Torvalds * Swedish University of Agricultural Sciences 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 81da177e4SLinus Torvalds * Ben Greear <greearb@candelatech.com> 91da177e4SLinus Torvalds * Jens L��s <jens.laas@data.slu.se> 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 121da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 131da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 141da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * A tool for loading the network with preconfigurated packets. 181da177e4SLinus Torvalds * The tool is implemented as a linux module. Parameters are output 191da177e4SLinus Torvalds * device, delay (to hard_xmit), number of packets, and whether 201da177e4SLinus Torvalds * to use multiple SKBs or just the same one. 211da177e4SLinus Torvalds * pktgen uses the installed interface's output routine. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * Additional hacking by: 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * Jens.Laas@data.slu.se 261da177e4SLinus Torvalds * Improved by ANK. 010120. 271da177e4SLinus Torvalds * Improved by ANK even more. 010212. 281da177e4SLinus Torvalds * MAC address typo fixed. 010417 --ro 291da177e4SLinus Torvalds * Integrated. 020301 --DaveM 301da177e4SLinus Torvalds * Added multiskb option 020301 --DaveM 311da177e4SLinus Torvalds * Scaling of results. 020417--sigurdur@linpro.no 321da177e4SLinus Torvalds * Significant re-work of the module: 331da177e4SLinus Torvalds * * Convert to threaded model to more efficiently be able to transmit 341da177e4SLinus Torvalds * and receive on multiple interfaces at once. 351da177e4SLinus Torvalds * * Converted many counters to __u64 to allow longer runs. 361da177e4SLinus Torvalds * * Allow configuration of ranges, like min/max IP address, MACs, 371da177e4SLinus Torvalds * and UDP-ports, for both source and destination, and can 381da177e4SLinus Torvalds * set to use a random distribution or sequentially walk the range. 391da177e4SLinus Torvalds * * Can now change most values after starting. 401da177e4SLinus Torvalds * * Place 12-byte packet in UDP payload with magic number, 411da177e4SLinus Torvalds * sequence number, and timestamp. 421da177e4SLinus Torvalds * * Add receiver code that detects dropped pkts, re-ordered pkts, and 431da177e4SLinus Torvalds * latencies (with micro-second) precision. 441da177e4SLinus Torvalds * * Add IOCTL interface to easily get counters & configuration. 451da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 461da177e4SLinus Torvalds * 471da177e4SLinus Torvalds * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 481da177e4SLinus Torvalds * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 491da177e4SLinus Torvalds * as a "fastpath" with a configurable number of clones after alloc's. 501da177e4SLinus Torvalds * clone_skb=0 means all packets are allocated this also means ranges time 511da177e4SLinus Torvalds * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 521da177e4SLinus Torvalds * clones. 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * Also moved to /proc/net/pktgen/ 551da177e4SLinus Torvalds * --ro 561da177e4SLinus Torvalds * 571da177e4SLinus Torvalds * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever 581da177e4SLinus Torvalds * mistakes. Also merged in DaveM's patch in the -pre6 patch. 591da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) 621da177e4SLinus Torvalds * 631da177e4SLinus Torvalds * 641da177e4SLinus Torvalds * 021124 Finished major redesign and rewrite for new functionality. 651da177e4SLinus Torvalds * See Documentation/networking/pktgen.txt for how to use this. 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * The new operation: 681da177e4SLinus Torvalds * For each CPU one thread/process is created at start. This process checks 691da177e4SLinus Torvalds * for running devices in the if_list and sends packets until count is 0 it 701da177e4SLinus Torvalds * also the thread checks the thread->control which is used for inter-process 711da177e4SLinus Torvalds * communication. controlling process "posts" operations to the threads this 721da177e4SLinus Torvalds * way. The if_lock should be possible to remove when add/rem_device is merged 731da177e4SLinus Torvalds * into this too. 741da177e4SLinus Torvalds * 751da177e4SLinus Torvalds * By design there should only be *one* "controlling" process. In practice 761da177e4SLinus Torvalds * multiple write accesses gives unpredictable result. Understood by "write" 771da177e4SLinus Torvalds * to /proc gives result code thats should be read be the "writer". 78b4099fabSStephen Hemminger * For practical use this should be no problem. 791da177e4SLinus Torvalds * 801da177e4SLinus Torvalds * Note when adding devices to a specific CPU there good idea to also assign 811da177e4SLinus Torvalds * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 821da177e4SLinus Torvalds * --ro 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * Fix refcount off by one if first packet fails, potential null deref, 851da177e4SLinus Torvalds * memleak 030710- KJP 861da177e4SLinus Torvalds * 871da177e4SLinus Torvalds * First "ranges" functionality for ipv6 030726 --ro 881da177e4SLinus Torvalds * 891da177e4SLinus Torvalds * Included flow support. 030802 ANK. 901da177e4SLinus Torvalds * 911da177e4SLinus Torvalds * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> 921da177e4SLinus Torvalds * 931da177e4SLinus Torvalds * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 941da177e4SLinus Torvalds * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 951da177e4SLinus Torvalds * 961da177e4SLinus Torvalds * New xmit() return, do_div and misc clean up by Stephen Hemminger 971da177e4SLinus Torvalds * <shemminger@osdl.org> 040923 981da177e4SLinus Torvalds * 99b4099fabSStephen Hemminger * Randy Dunlap fixed u64 printk compiler waring 1001da177e4SLinus Torvalds * 1011da177e4SLinus Torvalds * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> 1021da177e4SLinus Torvalds * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 1031da177e4SLinus Torvalds * 1041da177e4SLinus Torvalds * Corrections from Nikolai Malykh (nmalykh@bilim.com) 1051da177e4SLinus Torvalds * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 1061da177e4SLinus Torvalds * 1071da177e4SLinus Torvalds * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 1081da177e4SLinus Torvalds * 050103 109ca6549afSSteven Whitehouse * 110ca6549afSSteven Whitehouse * MPLS support by Steven Whitehouse <steve@chygwyn.com> 111ca6549afSSteven Whitehouse * 11234954ddcSFrancesco Fondelli * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> 11334954ddcSFrancesco Fondelli * 114*ce5d0b47SAdit Ranadive * Fixed src_mac command to set source mac of packet to value specified in 115*ce5d0b47SAdit Ranadive * command by Adit Ranadive <adit.262@gmail.com> 116*ce5d0b47SAdit Ranadive * 1171da177e4SLinus Torvalds */ 1181da177e4SLinus Torvalds #include <linux/sys.h> 1191da177e4SLinus Torvalds #include <linux/types.h> 1201da177e4SLinus Torvalds #include <linux/module.h> 1211da177e4SLinus Torvalds #include <linux/moduleparam.h> 1221da177e4SLinus Torvalds #include <linux/kernel.h> 123222fa076SLuiz Capitulino #include <linux/mutex.h> 1241da177e4SLinus Torvalds #include <linux/sched.h> 1251da177e4SLinus Torvalds #include <linux/slab.h> 1261da177e4SLinus Torvalds #include <linux/vmalloc.h> 1271da177e4SLinus Torvalds #include <linux/unistd.h> 1281da177e4SLinus Torvalds #include <linux/string.h> 1291da177e4SLinus Torvalds #include <linux/ptrace.h> 1301da177e4SLinus Torvalds #include <linux/errno.h> 1311da177e4SLinus Torvalds #include <linux/ioport.h> 1321da177e4SLinus Torvalds #include <linux/interrupt.h> 1334fc268d2SRandy Dunlap #include <linux/capability.h> 13409fe3ef4SAndrew Morton #include <linux/freezer.h> 1351da177e4SLinus Torvalds #include <linux/delay.h> 1361da177e4SLinus Torvalds #include <linux/timer.h> 137cdcdbe0bSLuiz Capitulino #include <linux/list.h> 1381da177e4SLinus Torvalds #include <linux/init.h> 1391da177e4SLinus Torvalds #include <linux/skbuff.h> 1401da177e4SLinus Torvalds #include <linux/netdevice.h> 1411da177e4SLinus Torvalds #include <linux/inet.h> 1421da177e4SLinus Torvalds #include <linux/inetdevice.h> 1431da177e4SLinus Torvalds #include <linux/rtnetlink.h> 1441da177e4SLinus Torvalds #include <linux/if_arp.h> 14534954ddcSFrancesco Fondelli #include <linux/if_vlan.h> 1461da177e4SLinus Torvalds #include <linux/in.h> 1471da177e4SLinus Torvalds #include <linux/ip.h> 1481da177e4SLinus Torvalds #include <linux/ipv6.h> 1491da177e4SLinus Torvalds #include <linux/udp.h> 1501da177e4SLinus Torvalds #include <linux/proc_fs.h> 151d50a6b56SStephen Hemminger #include <linux/seq_file.h> 1521da177e4SLinus Torvalds #include <linux/wait.h> 153f404e9a6SKris Katterjohn #include <linux/etherdevice.h> 154ee74baa7SDavid S. Miller #include <linux/kthread.h> 1551da177e4SLinus Torvalds #include <net/checksum.h> 1561da177e4SLinus Torvalds #include <net/ipv6.h> 1571da177e4SLinus Torvalds #include <net/addrconf.h> 158a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 159a553e4a6SJamal Hadi Salim #include <net/xfrm.h> 160a553e4a6SJamal Hadi Salim #endif 1611da177e4SLinus Torvalds #include <asm/byteorder.h> 1621da177e4SLinus Torvalds #include <linux/rcupdate.h> 1631da177e4SLinus Torvalds #include <asm/bitops.h> 1641da177e4SLinus Torvalds #include <asm/io.h> 1651da177e4SLinus Torvalds #include <asm/dma.h> 1661da177e4SLinus Torvalds #include <asm/uaccess.h> 1671da177e4SLinus Torvalds #include <asm/div64.h> /* do_div */ 1681da177e4SLinus Torvalds #include <asm/timex.h> 1691da177e4SLinus Torvalds 1701ca7768cSFrancesco Fondelli #define VERSION "pktgen v2.68: Packet Generator for packet performance testing.\n" 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds /* The buckets are exponential in 'width' */ 1731da177e4SLinus Torvalds #define LAT_BUCKETS_MAX 32 1741da177e4SLinus Torvalds #define IP_NAME_SZ 32 175ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ 176d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100) 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds /* Device flag bits */ 1791da177e4SLinus Torvalds #define F_IPSRC_RND (1<<0) /* IP-Src Random */ 1801da177e4SLinus Torvalds #define F_IPDST_RND (1<<1) /* IP-Dst Random */ 1811da177e4SLinus Torvalds #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ 1821da177e4SLinus Torvalds #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ 1831da177e4SLinus Torvalds #define F_MACSRC_RND (1<<4) /* MAC-Src Random */ 1841da177e4SLinus Torvalds #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ 1851da177e4SLinus Torvalds #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ 1861da177e4SLinus Torvalds #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ 187ca6549afSSteven Whitehouse #define F_MPLS_RND (1<<8) /* Random MPLS labels */ 18834954ddcSFrancesco Fondelli #define F_VID_RND (1<<9) /* Random VLAN ID */ 18934954ddcSFrancesco Fondelli #define F_SVID_RND (1<<10) /* Random SVLAN ID */ 190007a531bSJamal Hadi Salim #define F_FLOW_SEQ (1<<11) /* Sequential flows */ 191a553e4a6SJamal Hadi Salim #define F_IPSEC_ON (1<<12) /* ipsec on for flows */ 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* Thread control flag bits */ 1941da177e4SLinus Torvalds #define T_TERMINATE (1<<0) 1951da177e4SLinus Torvalds #define T_STOP (1<<1) /* Stop run */ 1961da177e4SLinus Torvalds #define T_RUN (1<<2) /* Start run */ 19795ed63f7SArthur Kepner #define T_REMDEVALL (1<<3) /* Remove all devs */ 19895ed63f7SArthur Kepner #define T_REMDEV (1<<4) /* Remove one dev */ 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds /* If lock -- can be removed after some work */ 2011da177e4SLinus Torvalds #define if_lock(t) spin_lock(&(t->if_lock)); 2021da177e4SLinus Torvalds #define if_unlock(t) spin_unlock(&(t->if_lock)); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 2051da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 206d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen" 207d50a6b56SStephen Hemminger #define PGCTRL "pgctrl" 208d50a6b56SStephen Hemminger static struct proc_dir_entry *pg_proc_dir = NULL; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds #define MAX_CFLOWS 65536 2111da177e4SLinus Torvalds 21234954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 21334954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 21434954ddcSFrancesco Fondelli 215222f1806SLuiz Capitulino struct flow_state { 216252e3346SAl Viro __be32 cur_daddr; 2171da177e4SLinus Torvalds int count; 218a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 219a553e4a6SJamal Hadi Salim struct xfrm_state *x; 220a553e4a6SJamal Hadi Salim #endif 221007a531bSJamal Hadi Salim __u32 flags; 2221da177e4SLinus Torvalds }; 2231da177e4SLinus Torvalds 224007a531bSJamal Hadi Salim /* flow flag bits */ 225007a531bSJamal Hadi Salim #define F_INIT (1<<0) /* flow has been initialized */ 226007a531bSJamal Hadi Salim 2271da177e4SLinus Torvalds struct pktgen_dev { 2281da177e4SLinus Torvalds /* 2291da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 2301da177e4SLinus Torvalds */ 23139df232fSStephen Hemminger struct proc_dir_entry *entry; /* proc file */ 2321da177e4SLinus Torvalds struct pktgen_thread *pg_thread;/* the owner */ 233c26a8016SLuiz Capitulino struct list_head list; /* Used for chaining in the thread's run-queue */ 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds int running; /* if this changes to false, the test will stop */ 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 2381da177e4SLinus Torvalds * we will do a random selection from within the range. 2391da177e4SLinus Torvalds */ 2401da177e4SLinus Torvalds __u32 flags; 24195ed63f7SArthur Kepner int removal_mark; /* non-zero => the device is marked for 24295ed63f7SArthur Kepner * removal by worker thread */ 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds int min_pkt_size; /* = ETH_ZLEN; */ 2451da177e4SLinus Torvalds int max_pkt_size; /* = ETH_ZLEN; */ 24616dab72fSJamal Hadi Salim int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2471da177e4SLinus Torvalds int nfrags; 2481da177e4SLinus Torvalds __u32 delay_us; /* Default delay */ 2491da177e4SLinus Torvalds __u32 delay_ns; 2501da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 2511da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 2521da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 2531da177e4SLinus Torvalds __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 2561da177e4SLinus Torvalds __u64 next_tx_us; /* timestamp of when to tx next */ 2571da177e4SLinus Torvalds __u32 next_tx_ns; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds __u64 allocated_skbs; 2601da177e4SLinus Torvalds __u32 clone_count; 2611da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 2621da177e4SLinus Torvalds * Or a failed transmit of some sort? This will keep 2631da177e4SLinus Torvalds * sequence numbers in order, for example. 2641da177e4SLinus Torvalds */ 2651da177e4SLinus Torvalds __u64 started_at; /* micro-seconds */ 2661da177e4SLinus Torvalds __u64 stopped_at; /* micro-seconds */ 2671da177e4SLinus Torvalds __u64 idle_acc; /* micro-seconds */ 2681da177e4SLinus Torvalds __u32 seq_num; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds int clone_skb; /* Use multiple SKBs during packet gen. If this number 271b4099fabSStephen Hemminger * is greater than 1, then that many copies of the same 2721da177e4SLinus Torvalds * packet will be sent before a new packet is allocated. 2731da177e4SLinus Torvalds * For instance, if you want to send 1024 identical packets 2741da177e4SLinus Torvalds * before creating a new packet, set clone_skb to 1024. 2751da177e4SLinus Torvalds */ 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2781da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2791da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2801da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds struct in6_addr in6_saddr; 2831da177e4SLinus Torvalds struct in6_addr in6_daddr; 2841da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 2851da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 2861da177e4SLinus Torvalds /* For ranges */ 2871da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 2881da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 2891da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 2901da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 2931da177e4SLinus Torvalds * defines the min/max for those ranges. 2941da177e4SLinus Torvalds */ 295252e3346SAl Viro __be32 saddr_min; /* inclusive, source IP address */ 296252e3346SAl Viro __be32 saddr_max; /* exclusive, source IP address */ 297252e3346SAl Viro __be32 daddr_min; /* inclusive, dest IP address */ 298252e3346SAl Viro __be32 daddr_max; /* exclusive, dest IP address */ 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 3011da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 3021da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 3031da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 3041da177e4SLinus Torvalds 3051ca7768cSFrancesco Fondelli /* DSCP + ECN */ 3061ca7768cSFrancesco Fondelli __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */ 3071ca7768cSFrancesco Fondelli __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */ 3081ca7768cSFrancesco Fondelli 309ca6549afSSteven Whitehouse /* MPLS */ 310ca6549afSSteven Whitehouse unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ 311ca6549afSSteven Whitehouse __be32 labels[MAX_MPLS_LABELS]; 312ca6549afSSteven Whitehouse 31334954ddcSFrancesco Fondelli /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 31434954ddcSFrancesco Fondelli __u8 vlan_p; 31534954ddcSFrancesco Fondelli __u8 vlan_cfi; 31634954ddcSFrancesco Fondelli __u16 vlan_id; /* 0xffff means no vlan tag */ 31734954ddcSFrancesco Fondelli 31834954ddcSFrancesco Fondelli __u8 svlan_p; 31934954ddcSFrancesco Fondelli __u8 svlan_cfi; 32034954ddcSFrancesco Fondelli __u16 svlan_id; /* 0xffff means no svlan tag */ 32134954ddcSFrancesco Fondelli 3221da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 3231da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 3241da177e4SLinus Torvalds 325f404e9a6SKris Katterjohn unsigned char dst_mac[ETH_ALEN]; 326f404e9a6SKris Katterjohn unsigned char src_mac[ETH_ALEN]; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 3291da177e4SLinus Torvalds __u32 cur_src_mac_offset; 330252e3346SAl Viro __be32 cur_saddr; 331252e3346SAl Viro __be32 cur_daddr; 3321da177e4SLinus Torvalds __u16 cur_udp_dst; 3331da177e4SLinus Torvalds __u16 cur_udp_src; 3341da177e4SLinus Torvalds __u32 cur_pkt_size; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds __u8 hh[14]; 3371da177e4SLinus Torvalds /* = { 3381da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds We fill in SRC address later 3411da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3421da177e4SLinus Torvalds 0x08, 0x00 3431da177e4SLinus Torvalds }; 3441da177e4SLinus Torvalds */ 3451da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds struct sk_buff *skb; /* skb we are to transmit next, mainly used for when we 3481da177e4SLinus Torvalds * are transmitting the same one multiple times 3491da177e4SLinus Torvalds */ 3501da177e4SLinus Torvalds struct net_device *odev; /* The out-going device. Note that the device should 3511da177e4SLinus Torvalds * have it's pg_info pointer pointing back to this 3521da177e4SLinus Torvalds * device. This will be set when the user specifies 3531da177e4SLinus Torvalds * the out-going device name (not when the inject is 3541da177e4SLinus Torvalds * started as it used to do.) 3551da177e4SLinus Torvalds */ 3561da177e4SLinus Torvalds struct flow_state *flows; 3571da177e4SLinus Torvalds unsigned cflows; /* Concurrent flows (config) */ 3581da177e4SLinus Torvalds unsigned lflow; /* Flow length (config) */ 3591da177e4SLinus Torvalds unsigned nflows; /* accumulated flows (stats) */ 360007a531bSJamal Hadi Salim unsigned curfl; /* current sequenced flow (state)*/ 361a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 362a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 363a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 364a553e4a6SJamal Hadi Salim #endif 36539df232fSStephen Hemminger char result[512]; 3661da177e4SLinus Torvalds }; 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds struct pktgen_hdr { 369252e3346SAl Viro __be32 pgh_magic; 370252e3346SAl Viro __be32 seq_num; 371252e3346SAl Viro __be32 tv_sec; 372252e3346SAl Viro __be32 tv_usec; 3731da177e4SLinus Torvalds }; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds struct pktgen_thread { 3761da177e4SLinus Torvalds spinlock_t if_lock; 377c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 378cdcdbe0bSLuiz Capitulino struct list_head th_list; 379ee74baa7SDavid S. Miller struct task_struct *tsk; 3801da177e4SLinus Torvalds char result[512]; 3811da177e4SLinus Torvalds u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds /* Field for thread to receive "posted" events terminate, stop ifs etc. */ 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds u32 control; 3861da177e4SLinus Torvalds int cpu; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds wait_queue_head_t queue; 3891da177e4SLinus Torvalds }; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds #define REMOVE 1 3921da177e4SLinus Torvalds #define FIND 0 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds /* This code works around the fact that do_div cannot handle two 64-bit 3951da177e4SLinus Torvalds numbers, and regular 64-bit division doesn't work on x86 kernels. 3961da177e4SLinus Torvalds --Ben 3971da177e4SLinus Torvalds */ 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds #define PG_DIV 0 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* This was emailed to LMKL by: Chris Caputo <ccaputo@alt.net> 4021da177e4SLinus Torvalds * Function copied/adapted/optimized from: 4031da177e4SLinus Torvalds * 4041da177e4SLinus Torvalds * nemesis.sourceforge.net/browse/lib/static/intmath/ix86/intmath.c.html 4051da177e4SLinus Torvalds * 4061da177e4SLinus Torvalds * Copyright 1994, University of Cambridge Computer Laboratory 4071da177e4SLinus Torvalds * All Rights Reserved. 4081da177e4SLinus Torvalds * 4091da177e4SLinus Torvalds */ 41077933d72SJesper Juhl static inline s64 divremdi3(s64 x, s64 y, int type) 4111da177e4SLinus Torvalds { 4121da177e4SLinus Torvalds u64 a = (x < 0) ? -x : x; 4131da177e4SLinus Torvalds u64 b = (y < 0) ? -y : y; 4141da177e4SLinus Torvalds u64 res = 0, d = 1; 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds if (b > 0) { 4171da177e4SLinus Torvalds while (b < a) { 4181da177e4SLinus Torvalds b <<= 1; 4191da177e4SLinus Torvalds d <<= 1; 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds } 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds do { 4241da177e4SLinus Torvalds if (a >= b) { 4251da177e4SLinus Torvalds a -= b; 4261da177e4SLinus Torvalds res += d; 4271da177e4SLinus Torvalds } 4281da177e4SLinus Torvalds b >>= 1; 4291da177e4SLinus Torvalds d >>= 1; 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds while (d); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds if (PG_DIV == type) { 4341da177e4SLinus Torvalds return (((x ^ y) & (1ll << 63)) == 0) ? res : -(s64) res; 435222f1806SLuiz Capitulino } else { 4361da177e4SLinus Torvalds return ((x & (1ll << 63)) == 0) ? a : -(s64) a; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* End of hacks to deal with 64-bit math on x86 */ 4411da177e4SLinus Torvalds 442b4099fabSStephen Hemminger /** Convert to milliseconds */ 4431da177e4SLinus Torvalds static inline __u64 tv_to_ms(const struct timeval *tv) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds __u64 ms = tv->tv_usec / 1000; 4461da177e4SLinus Torvalds ms += (__u64) tv->tv_sec * (__u64) 1000; 4471da177e4SLinus Torvalds return ms; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds /** Convert to micro-seconds */ 4511da177e4SLinus Torvalds static inline __u64 tv_to_us(const struct timeval *tv) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds __u64 us = tv->tv_usec; 4541da177e4SLinus Torvalds us += (__u64) tv->tv_sec * (__u64) 1000000; 4551da177e4SLinus Torvalds return us; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 458222f1806SLuiz Capitulino static inline __u64 pg_div(__u64 n, __u32 base) 459222f1806SLuiz Capitulino { 4601da177e4SLinus Torvalds __u64 tmp = n; 4611da177e4SLinus Torvalds do_div(tmp, base); 4621da177e4SLinus Torvalds /* printk("pktgen: pg_div, n: %llu base: %d rv: %llu\n", 4631da177e4SLinus Torvalds n, base, tmp); */ 4641da177e4SLinus Torvalds return tmp; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds static inline __u64 pg_div64(__u64 n, __u64 base) 4681da177e4SLinus Torvalds { 4691da177e4SLinus Torvalds __u64 tmp = n; 4701da177e4SLinus Torvalds /* 471b4099fabSStephen Hemminger * How do we know if the architecture we are running on 4721da177e4SLinus Torvalds * supports division with 64 bit base? 4731da177e4SLinus Torvalds * 4741da177e4SLinus Torvalds */ 4751da177e4SLinus Torvalds #if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__) 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds do_div(tmp, base); 4781da177e4SLinus Torvalds #else 4791da177e4SLinus Torvalds tmp = divremdi3(n, base, PG_DIV); 4801da177e4SLinus Torvalds #endif 4811da177e4SLinus Torvalds return tmp; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds static inline __u64 getCurMs(void) 4851da177e4SLinus Torvalds { 4861da177e4SLinus Torvalds struct timeval tv; 4871da177e4SLinus Torvalds do_gettimeofday(&tv); 4881da177e4SLinus Torvalds return tv_to_ms(&tv); 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds static inline __u64 getCurUs(void) 4921da177e4SLinus Torvalds { 4931da177e4SLinus Torvalds struct timeval tv; 4941da177e4SLinus Torvalds do_gettimeofday(&tv); 4951da177e4SLinus Torvalds return tv_to_us(&tv); 4961da177e4SLinus Torvalds } 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds static inline __u64 tv_diff(const struct timeval *a, const struct timeval *b) 4991da177e4SLinus Torvalds { 5001da177e4SLinus Torvalds return tv_to_us(a) - tv_to_us(b); 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds /* old include end */ 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds static char version[] __initdata = VERSION; 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 5081da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 509222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 510222f1806SLuiz Capitulino const char *ifname); 5111da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 5121da177e4SLinus Torvalds static void pktgen_run_all_threads(void); 5131da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void); 5141da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev); 5151da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 5161da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 51739df232fSStephen Hemminger 5181da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]); 5191da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s, const char ip[16]); 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds /* Module parameters, defaults. */ 5221da177e4SLinus Torvalds static int pg_count_d = 1000; /* 1000 pkts by default */ 523f34fbb97SJaco Kroon static int pg_delay_d; 524f34fbb97SJaco Kroon static int pg_clone_skb_d; 525f34fbb97SJaco Kroon static int debug; 5261da177e4SLinus Torvalds 527222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 528cdcdbe0bSLuiz Capitulino static LIST_HEAD(pktgen_threads); 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 5311da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 5321da177e4SLinus Torvalds }; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /* 5351da177e4SLinus Torvalds * /proc handling functions 5361da177e4SLinus Torvalds * 5371da177e4SLinus Torvalds */ 5381da177e4SLinus Torvalds 539d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 540d50a6b56SStephen Hemminger { 541d50a6b56SStephen Hemminger seq_puts(seq, VERSION); 542d50a6b56SStephen Hemminger return 0; 543d50a6b56SStephen Hemminger } 5441da177e4SLinus Torvalds 545d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user * buf, 5461da177e4SLinus Torvalds size_t count, loff_t * ppos) 5471da177e4SLinus Torvalds { 5481da177e4SLinus Torvalds int err = 0; 549d50a6b56SStephen Hemminger char data[128]; 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) { 5521da177e4SLinus Torvalds err = -EPERM; 5531da177e4SLinus Torvalds goto out; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 556d50a6b56SStephen Hemminger if (count > sizeof(data)) 557d50a6b56SStephen Hemminger count = sizeof(data); 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds if (copy_from_user(data, buf, count)) { 5601da177e4SLinus Torvalds err = -EFAULT; 561d50a6b56SStephen Hemminger goto out; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds data[count - 1] = 0; /* Make string */ 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds if (!strcmp(data, "stop")) 5661da177e4SLinus Torvalds pktgen_stop_all_threads_ifs(); 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds else if (!strcmp(data, "start")) 5691da177e4SLinus Torvalds pktgen_run_all_threads(); 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds else 57225a8b254SDavid S. Miller printk(KERN_WARNING "pktgen: Unknown command: %s\n", data); 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds err = count; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds out: 5771da177e4SLinus Torvalds return err; 5781da177e4SLinus Torvalds } 5791da177e4SLinus Torvalds 580d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5811da177e4SLinus Torvalds { 582d50a6b56SStephen Hemminger return single_open(file, pgctrl_show, PDE(inode)->data); 583d50a6b56SStephen Hemminger } 584d50a6b56SStephen Hemminger 5859a32144eSArjan van de Ven static const struct file_operations pktgen_fops = { 586d50a6b56SStephen Hemminger .owner = THIS_MODULE, 587d50a6b56SStephen Hemminger .open = pgctrl_open, 588d50a6b56SStephen Hemminger .read = seq_read, 589d50a6b56SStephen Hemminger .llseek = seq_lseek, 590d50a6b56SStephen Hemminger .write = pgctrl_write, 591d50a6b56SStephen Hemminger .release = single_release, 592d50a6b56SStephen Hemminger }; 593d50a6b56SStephen Hemminger 594d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 595d50a6b56SStephen Hemminger { 5961da177e4SLinus Torvalds int i; 597d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 5981da177e4SLinus Torvalds __u64 sa; 5991da177e4SLinus Torvalds __u64 stopped; 6001da177e4SLinus Torvalds __u64 now = getCurUs(); 6011da177e4SLinus Torvalds 602222f1806SLuiz Capitulino seq_printf(seq, 603222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 604222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 605222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 6061da177e4SLinus Torvalds 607222f1806SLuiz Capitulino seq_printf(seq, 608222f1806SLuiz Capitulino " frags: %d delay: %u clone_skb: %d ifname: %s\n", 609222f1806SLuiz Capitulino pkt_dev->nfrags, 610222f1806SLuiz Capitulino 1000 * pkt_dev->delay_us + pkt_dev->delay_ns, 61139df232fSStephen Hemminger pkt_dev->clone_skb, pkt_dev->odev->name); 6121da177e4SLinus Torvalds 613222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 614222f1806SLuiz Capitulino pkt_dev->lflow); 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 6171da177e4SLinus Torvalds char b1[128], b2[128], b3[128]; 6181da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); 6191da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); 6201da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); 621222f1806SLuiz Capitulino seq_printf(seq, 622222f1806SLuiz Capitulino " saddr: %s min_saddr: %s max_saddr: %s\n", b1, 623222f1806SLuiz Capitulino b2, b3); 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); 6261da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); 6271da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); 628222f1806SLuiz Capitulino seq_printf(seq, 629222f1806SLuiz Capitulino " daddr: %s min_daddr: %s max_daddr: %s\n", b1, 630222f1806SLuiz Capitulino b2, b3); 6311da177e4SLinus Torvalds 632222f1806SLuiz Capitulino } else 633222f1806SLuiz Capitulino seq_printf(seq, 634222f1806SLuiz Capitulino " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", 635222f1806SLuiz Capitulino pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, 636222f1806SLuiz Capitulino pkt_dev->src_max); 6371da177e4SLinus Torvalds 638d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 6391da177e4SLinus Torvalds 640f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 6411da177e4SLinus Torvalds for (i = 0; i < 6; i++) 642222f1806SLuiz Capitulino seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i], 643222f1806SLuiz Capitulino i == 5 ? " " : ":"); 6441da177e4SLinus Torvalds else 6451da177e4SLinus Torvalds for (i = 0; i < 6; i++) 646222f1806SLuiz Capitulino seq_printf(seq, "%02X%s", pkt_dev->src_mac[i], 647222f1806SLuiz Capitulino i == 5 ? " " : ":"); 6481da177e4SLinus Torvalds 649d50a6b56SStephen Hemminger seq_printf(seq, "dst_mac: "); 6501da177e4SLinus Torvalds for (i = 0; i < 6; i++) 651222f1806SLuiz Capitulino seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i], 652222f1806SLuiz Capitulino i == 5 ? "\n" : ":"); 6531da177e4SLinus Torvalds 654222f1806SLuiz Capitulino seq_printf(seq, 655222f1806SLuiz Capitulino " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", 656222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 657222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 6581da177e4SLinus Torvalds 659222f1806SLuiz Capitulino seq_printf(seq, 660ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 6611da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 6621da177e4SLinus Torvalds 663ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 664ca6549afSSteven Whitehouse unsigned i; 665ca6549afSSteven Whitehouse seq_printf(seq, " mpls: "); 666ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 667ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 668ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 669ca6549afSSteven Whitehouse } 670ca6549afSSteven Whitehouse 67134954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 67234954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 67334954ddcSFrancesco Fondelli pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi); 67434954ddcSFrancesco Fondelli } 67534954ddcSFrancesco Fondelli 67634954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 67734954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 67834954ddcSFrancesco Fondelli pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi); 67934954ddcSFrancesco Fondelli } 68034954ddcSFrancesco Fondelli 6811ca7768cSFrancesco Fondelli if (pkt_dev->tos) { 6821ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6831ca7768cSFrancesco Fondelli } 6841ca7768cSFrancesco Fondelli 6851ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 6861ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6871ca7768cSFrancesco Fondelli } 6881ca7768cSFrancesco Fondelli 689ca6549afSSteven Whitehouse seq_printf(seq, " Flags: "); 690ca6549afSSteven Whitehouse 6911da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 692d50a6b56SStephen Hemminger seq_printf(seq, "IPV6 "); 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 695d50a6b56SStephen Hemminger seq_printf(seq, "IPSRC_RND "); 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 698d50a6b56SStephen Hemminger seq_printf(seq, "IPDST_RND "); 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 701d50a6b56SStephen Hemminger seq_printf(seq, "TXSIZE_RND "); 7021da177e4SLinus Torvalds 7031da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 704d50a6b56SStephen Hemminger seq_printf(seq, "UDPSRC_RND "); 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 707d50a6b56SStephen Hemminger seq_printf(seq, "UDPDST_RND "); 7081da177e4SLinus Torvalds 709ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) 710ca6549afSSteven Whitehouse seq_printf(seq, "MPLS_RND "); 711ca6549afSSteven Whitehouse 712007a531bSJamal Hadi Salim if (pkt_dev->cflows) { 713007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) 714007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/ 715007a531bSJamal Hadi Salim else 716007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_RND "); 717007a531bSJamal Hadi Salim } 718007a531bSJamal Hadi Salim 719a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 720a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 721a553e4a6SJamal Hadi Salim seq_printf(seq, "IPSEC "); 722a553e4a6SJamal Hadi Salim #endif 723a553e4a6SJamal Hadi Salim 7241da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 725d50a6b56SStephen Hemminger seq_printf(seq, "MACSRC_RND "); 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 728d50a6b56SStephen Hemminger seq_printf(seq, "MACDST_RND "); 7291da177e4SLinus Torvalds 73034954ddcSFrancesco Fondelli if (pkt_dev->flags & F_VID_RND) 73134954ddcSFrancesco Fondelli seq_printf(seq, "VID_RND "); 73234954ddcSFrancesco Fondelli 73334954ddcSFrancesco Fondelli if (pkt_dev->flags & F_SVID_RND) 73434954ddcSFrancesco Fondelli seq_printf(seq, "SVID_RND "); 73534954ddcSFrancesco Fondelli 736d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds sa = pkt_dev->started_at; 7391da177e4SLinus Torvalds stopped = pkt_dev->stopped_at; 7401da177e4SLinus Torvalds if (pkt_dev->running) 7411da177e4SLinus Torvalds stopped = now; /* not really stopped, more like last-running-at */ 7421da177e4SLinus Torvalds 743222f1806SLuiz Capitulino seq_printf(seq, 744222f1806SLuiz Capitulino "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", 7451da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 746222f1806SLuiz Capitulino (unsigned long long)pkt_dev->errors, (unsigned long long)sa, 7471da177e4SLinus Torvalds (unsigned long long)stopped, 7481da177e4SLinus Torvalds (unsigned long long)pkt_dev->idle_acc); 7491da177e4SLinus Torvalds 750222f1806SLuiz Capitulino seq_printf(seq, 751222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 752d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 753d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 7561da177e4SLinus Torvalds char b1[128], b2[128]; 7571da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); 7581da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); 759d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); 760222f1806SLuiz Capitulino } else 761d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", 7621da177e4SLinus Torvalds pkt_dev->cur_saddr, pkt_dev->cur_daddr); 7631da177e4SLinus Torvalds 764d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7651da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7661da177e4SLinus Torvalds 767d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds if (pkt_dev->result[0]) 770d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7711da177e4SLinus Torvalds else 772d50a6b56SStephen Hemminger seq_printf(seq, "Result: Idle\n"); 7731da177e4SLinus Torvalds 774d50a6b56SStephen Hemminger return 0; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 777ca6549afSSteven Whitehouse 7781ca7768cSFrancesco Fondelli static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num) 779ca6549afSSteven Whitehouse { 780ca6549afSSteven Whitehouse int i = 0; 781ca6549afSSteven Whitehouse *num = 0; 782ca6549afSSteven Whitehouse 7831ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 784ca6549afSSteven Whitehouse char c; 785ca6549afSSteven Whitehouse *num <<= 4; 786ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 787ca6549afSSteven Whitehouse return -EFAULT; 788ca6549afSSteven Whitehouse if ((c >= '0') && (c <= '9')) 789ca6549afSSteven Whitehouse *num |= c - '0'; 790ca6549afSSteven Whitehouse else if ((c >= 'a') && (c <= 'f')) 791ca6549afSSteven Whitehouse *num |= c - 'a' + 10; 792ca6549afSSteven Whitehouse else if ((c >= 'A') && (c <= 'F')) 793ca6549afSSteven Whitehouse *num |= c - 'A' + 10; 794ca6549afSSteven Whitehouse else 795ca6549afSSteven Whitehouse break; 796ca6549afSSteven Whitehouse } 797ca6549afSSteven Whitehouse return i; 798ca6549afSSteven Whitehouse } 799ca6549afSSteven Whitehouse 800222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 801222f1806SLuiz Capitulino unsigned int maxlen) 8021da177e4SLinus Torvalds { 8031da177e4SLinus Torvalds int i; 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 8061da177e4SLinus Torvalds char c; 8071da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8081da177e4SLinus Torvalds return -EFAULT; 8091da177e4SLinus Torvalds switch (c) { 8101da177e4SLinus Torvalds case '\"': 8111da177e4SLinus Torvalds case '\n': 8121da177e4SLinus Torvalds case '\r': 8131da177e4SLinus Torvalds case '\t': 8141da177e4SLinus Torvalds case ' ': 8151da177e4SLinus Torvalds case '=': 8161da177e4SLinus Torvalds break; 8171da177e4SLinus Torvalds default: 8181da177e4SLinus Torvalds goto done; 8193ff50b79SStephen Hemminger } 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds done: 8221da177e4SLinus Torvalds return i; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 825222f1806SLuiz Capitulino static unsigned long num_arg(const char __user * user_buffer, 826222f1806SLuiz Capitulino unsigned long maxlen, unsigned long *num) 8271da177e4SLinus Torvalds { 8281da177e4SLinus Torvalds int i = 0; 8291da177e4SLinus Torvalds *num = 0; 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds for (; i < maxlen; i++) { 8321da177e4SLinus Torvalds char c; 8331da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8341da177e4SLinus Torvalds return -EFAULT; 8351da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 8361da177e4SLinus Torvalds *num *= 10; 8371da177e4SLinus Torvalds *num += c - '0'; 8381da177e4SLinus Torvalds } else 8391da177e4SLinus Torvalds break; 8401da177e4SLinus Torvalds } 8411da177e4SLinus Torvalds return i; 8421da177e4SLinus Torvalds } 8431da177e4SLinus Torvalds 8441da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 8451da177e4SLinus Torvalds { 8461da177e4SLinus Torvalds int i = 0; 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds for (; i < maxlen; i++) { 8491da177e4SLinus Torvalds char c; 8501da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8511da177e4SLinus Torvalds return -EFAULT; 8521da177e4SLinus Torvalds switch (c) { 8531da177e4SLinus Torvalds case '\"': 8541da177e4SLinus Torvalds case '\n': 8551da177e4SLinus Torvalds case '\r': 8561da177e4SLinus Torvalds case '\t': 8571da177e4SLinus Torvalds case ' ': 8581da177e4SLinus Torvalds goto done_str; 8591da177e4SLinus Torvalds break; 8601da177e4SLinus Torvalds default: 8611da177e4SLinus Torvalds break; 8623ff50b79SStephen Hemminger } 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds done_str: 8651da177e4SLinus Torvalds return i; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 868ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 869ca6549afSSteven Whitehouse { 870ca6549afSSteven Whitehouse unsigned n = 0; 871ca6549afSSteven Whitehouse char c; 872ca6549afSSteven Whitehouse ssize_t i = 0; 873ca6549afSSteven Whitehouse int len; 874ca6549afSSteven Whitehouse 875ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 876ca6549afSSteven Whitehouse do { 877ca6549afSSteven Whitehouse __u32 tmp; 8781ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 879ca6549afSSteven Whitehouse if (len <= 0) 880ca6549afSSteven Whitehouse return len; 881ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 882ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 883ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 884ca6549afSSteven Whitehouse i += len; 885ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 886ca6549afSSteven Whitehouse return -EFAULT; 887ca6549afSSteven Whitehouse i++; 888ca6549afSSteven Whitehouse n++; 889ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 890ca6549afSSteven Whitehouse return -E2BIG; 891ca6549afSSteven Whitehouse } while (c == ','); 892ca6549afSSteven Whitehouse 893ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 894ca6549afSSteven Whitehouse return i; 895ca6549afSSteven Whitehouse } 896ca6549afSSteven Whitehouse 897222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 898222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 899222f1806SLuiz Capitulino loff_t * offset) 9001da177e4SLinus Torvalds { 901d50a6b56SStephen Hemminger struct seq_file *seq = (struct seq_file *)file->private_data; 902d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 9031da177e4SLinus Torvalds int i = 0, max, len; 9041da177e4SLinus Torvalds char name[16], valstr[32]; 9051da177e4SLinus Torvalds unsigned long value = 0; 9061da177e4SLinus Torvalds char *pg_result = NULL; 9071da177e4SLinus Torvalds int tmp = 0; 9081da177e4SLinus Torvalds char buf[128]; 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds if (count < 1) { 91325a8b254SDavid S. Miller printk(KERN_WARNING "pktgen: wrong command format\n"); 9141da177e4SLinus Torvalds return -EINVAL; 9151da177e4SLinus Torvalds } 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds max = count - i; 9181da177e4SLinus Torvalds tmp = count_trail_chars(&user_buffer[i], max); 9191da177e4SLinus Torvalds if (tmp < 0) { 92025a8b254SDavid S. Miller printk(KERN_WARNING "pktgen: illegal format\n"); 9211da177e4SLinus Torvalds return tmp; 9221da177e4SLinus Torvalds } 9231da177e4SLinus Torvalds i += tmp; 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds /* Read variable name */ 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 928222f1806SLuiz Capitulino if (len < 0) { 929222f1806SLuiz Capitulino return len; 930222f1806SLuiz Capitulino } 9311da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 9321da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 9331da177e4SLinus Torvalds return -EFAULT; 9341da177e4SLinus Torvalds i += len; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds max = count - i; 9371da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 9381da177e4SLinus Torvalds if (len < 0) 9391da177e4SLinus Torvalds return len; 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds i += len; 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds if (debug) { 9441da177e4SLinus Torvalds char tb[count + 1]; 9451da177e4SLinus Torvalds if (copy_from_user(tb, user_buffer, count)) 9461da177e4SLinus Torvalds return -EFAULT; 9471da177e4SLinus Torvalds tb[count] = 0; 94825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, 949d50a6b56SStephen Hemminger (unsigned long)count, tb); 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9531da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 954222f1806SLuiz Capitulino if (len < 0) { 955222f1806SLuiz Capitulino return len; 956222f1806SLuiz Capitulino } 9571da177e4SLinus Torvalds i += len; 9581da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9591da177e4SLinus Torvalds value = 14 + 20 + 8; 9601da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9611da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9621da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9631da177e4SLinus Torvalds } 964222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 965222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9661da177e4SLinus Torvalds return count; 9671da177e4SLinus Torvalds } 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9701da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 971222f1806SLuiz Capitulino if (len < 0) { 972222f1806SLuiz Capitulino return len; 973222f1806SLuiz Capitulino } 9741da177e4SLinus Torvalds i += len; 9751da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9761da177e4SLinus Torvalds value = 14 + 20 + 8; 9771da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9781da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9791da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9801da177e4SLinus Torvalds } 981222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 982222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9831da177e4SLinus Torvalds return count; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds /* Shortcut for min = max */ 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9891da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 990222f1806SLuiz Capitulino if (len < 0) { 991222f1806SLuiz Capitulino return len; 992222f1806SLuiz Capitulino } 9931da177e4SLinus Torvalds i += len; 9941da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9951da177e4SLinus Torvalds value = 14 + 20 + 8; 9961da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9971da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9981da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9991da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 10021da177e4SLinus Torvalds return count; 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 10061da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1007222f1806SLuiz Capitulino if (len < 0) { 1008222f1806SLuiz Capitulino return len; 1009222f1806SLuiz Capitulino } 10101da177e4SLinus Torvalds i += len; 10111da177e4SLinus Torvalds debug = value; 10121da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 10131da177e4SLinus Torvalds return count; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 10171da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1018222f1806SLuiz Capitulino if (len < 0) { 1019222f1806SLuiz Capitulino return len; 1020222f1806SLuiz Capitulino } 10211da177e4SLinus Torvalds i += len; 10221da177e4SLinus Torvalds pkt_dev->nfrags = value; 10231da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 10241da177e4SLinus Torvalds return count; 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 10271da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1028222f1806SLuiz Capitulino if (len < 0) { 1029222f1806SLuiz Capitulino return len; 1030222f1806SLuiz Capitulino } 10311da177e4SLinus Torvalds i += len; 10321da177e4SLinus Torvalds if (value == 0x7FFFFFFF) { 10331da177e4SLinus Torvalds pkt_dev->delay_us = 0x7FFFFFFF; 10341da177e4SLinus Torvalds pkt_dev->delay_ns = 0; 10351da177e4SLinus Torvalds } else { 10361da177e4SLinus Torvalds pkt_dev->delay_us = value / 1000; 10371da177e4SLinus Torvalds pkt_dev->delay_ns = value % 1000; 10381da177e4SLinus Torvalds } 1039222f1806SLuiz Capitulino sprintf(pg_result, "OK: delay=%u", 1040222f1806SLuiz Capitulino 1000 * pkt_dev->delay_us + pkt_dev->delay_ns); 10411da177e4SLinus Torvalds return count; 10421da177e4SLinus Torvalds } 10431da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10441da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1045222f1806SLuiz Capitulino if (len < 0) { 1046222f1806SLuiz Capitulino return len; 1047222f1806SLuiz Capitulino } 10481da177e4SLinus Torvalds i += len; 10491da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10501da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10511da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10541da177e4SLinus Torvalds return count; 10551da177e4SLinus Torvalds } 10561da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10571da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1058222f1806SLuiz Capitulino if (len < 0) { 1059222f1806SLuiz Capitulino return len; 1060222f1806SLuiz Capitulino } 10611da177e4SLinus Torvalds i += len; 10621da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10631da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10641da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10671da177e4SLinus Torvalds return count; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10701da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1071222f1806SLuiz Capitulino if (len < 0) { 1072222f1806SLuiz Capitulino return len; 1073222f1806SLuiz Capitulino } 10741da177e4SLinus Torvalds i += len; 10751da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10761da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10771da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10801da177e4SLinus Torvalds return count; 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10831da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1084222f1806SLuiz Capitulino if (len < 0) { 1085222f1806SLuiz Capitulino return len; 1086222f1806SLuiz Capitulino } 10871da177e4SLinus Torvalds i += len; 10881da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10891da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10901da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10911da177e4SLinus Torvalds } 10921da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10931da177e4SLinus Torvalds return count; 10941da177e4SLinus Torvalds } 10951da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10961da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1097222f1806SLuiz Capitulino if (len < 0) { 1098222f1806SLuiz Capitulino return len; 1099222f1806SLuiz Capitulino } 11001da177e4SLinus Torvalds i += len; 11011da177e4SLinus Torvalds pkt_dev->clone_skb = value; 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 11041da177e4SLinus Torvalds return count; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds if (!strcmp(name, "count")) { 11071da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1108222f1806SLuiz Capitulino if (len < 0) { 1109222f1806SLuiz Capitulino return len; 1110222f1806SLuiz Capitulino } 11111da177e4SLinus Torvalds i += len; 11121da177e4SLinus Torvalds pkt_dev->count = value; 11131da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 11141da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 11151da177e4SLinus Torvalds return count; 11161da177e4SLinus Torvalds } 11171da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 11181da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1119222f1806SLuiz Capitulino if (len < 0) { 1120222f1806SLuiz Capitulino return len; 1121222f1806SLuiz Capitulino } 11221da177e4SLinus Torvalds i += len; 11231da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 11241da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11251da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11261da177e4SLinus Torvalds } 1127222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1128222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11291da177e4SLinus Torvalds return count; 11301da177e4SLinus Torvalds } 11311da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11321da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1133222f1806SLuiz Capitulino if (len < 0) { 1134222f1806SLuiz Capitulino return len; 1135222f1806SLuiz Capitulino } 11361da177e4SLinus Torvalds i += len; 11371da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11381da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11391da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11401da177e4SLinus Torvalds } 1141222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1142222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11431da177e4SLinus Torvalds return count; 11441da177e4SLinus Torvalds } 11451da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 11461da177e4SLinus Torvalds char f[32]; 11471da177e4SLinus Torvalds memset(f, 0, 32); 11481da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 1149222f1806SLuiz Capitulino if (len < 0) { 1150222f1806SLuiz Capitulino return len; 1151222f1806SLuiz Capitulino } 11521da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 11531da177e4SLinus Torvalds return -EFAULT; 11541da177e4SLinus Torvalds i += len; 11551da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 11561da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 11591da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 11621da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 11651da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 11681da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 11711da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 11721da177e4SLinus Torvalds 11731da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 11741da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 11771da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 11801da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 11831da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 11841da177e4SLinus Torvalds 11851da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 11861da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 11891da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 11921da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 11951da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 11961da177e4SLinus Torvalds 1197ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1198ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1199ca6549afSSteven Whitehouse 1200ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1201ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1202ca6549afSSteven Whitehouse 120334954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 120434954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 120534954ddcSFrancesco Fondelli 120634954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 120734954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 120834954ddcSFrancesco Fondelli 120934954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 121034954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 121134954ddcSFrancesco Fondelli 121234954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 121334954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 121434954ddcSFrancesco Fondelli 1215007a531bSJamal Hadi Salim else if (strcmp(f, "FLOW_SEQ") == 0) 1216007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1217007a531bSJamal Hadi Salim 1218a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1219a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1220a553e4a6SJamal Hadi Salim pkt_dev->flags |= F_IPSEC_ON; 1221a553e4a6SJamal Hadi Salim #endif 1222a553e4a6SJamal Hadi Salim 12231ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 12241ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 12251ca7768cSFrancesco Fondelli 12261da177e4SLinus Torvalds else { 1227222f1806SLuiz Capitulino sprintf(pg_result, 1228222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12291da177e4SLinus Torvalds f, 12301ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 1231a553e4a6SJamal Hadi Salim "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n"); 12321da177e4SLinus Torvalds return count; 12331da177e4SLinus Torvalds } 12341da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12351da177e4SLinus Torvalds return count; 12361da177e4SLinus Torvalds } 12371da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12381da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 1239222f1806SLuiz Capitulino if (len < 0) { 1240222f1806SLuiz Capitulino return len; 1241222f1806SLuiz Capitulino } 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12441da177e4SLinus Torvalds return -EFAULT; 12451da177e4SLinus Torvalds buf[len] = 0; 12461da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12471da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12481da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 12491da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12501da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds if (debug) 125325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_min set to: %s\n", 1254222f1806SLuiz Capitulino pkt_dev->dst_min); 12551da177e4SLinus Torvalds i += len; 12561da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12571da177e4SLinus Torvalds return count; 12581da177e4SLinus Torvalds } 12591da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12601da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 1261222f1806SLuiz Capitulino if (len < 0) { 1262222f1806SLuiz Capitulino return len; 1263222f1806SLuiz Capitulino } 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12661da177e4SLinus Torvalds return -EFAULT; 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds buf[len] = 0; 12691da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 12701da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 12711da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 12721da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12731da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 12741da177e4SLinus Torvalds } 12751da177e4SLinus Torvalds if (debug) 127625a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_max set to: %s\n", 1277222f1806SLuiz Capitulino pkt_dev->dst_max); 12781da177e4SLinus Torvalds i += len; 12791da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12801da177e4SLinus Torvalds return count; 12811da177e4SLinus Torvalds } 12821da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 12831da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1284222f1806SLuiz Capitulino if (len < 0) 1285222f1806SLuiz Capitulino return len; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12901da177e4SLinus Torvalds return -EFAULT; 12911da177e4SLinus Torvalds buf[len] = 0; 12921da177e4SLinus Torvalds 12931da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); 12941da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); 12971da177e4SLinus Torvalds 12981da177e4SLinus Torvalds if (debug) 129925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf); 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds i += len; 13021da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13031da177e4SLinus Torvalds return count; 13041da177e4SLinus Torvalds } 13051da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13061da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1307222f1806SLuiz Capitulino if (len < 0) 1308222f1806SLuiz Capitulino return len; 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13111da177e4SLinus Torvalds 13121da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13131da177e4SLinus Torvalds return -EFAULT; 13141da177e4SLinus Torvalds buf[len] = 0; 13151da177e4SLinus Torvalds 13161da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13171da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13181da177e4SLinus Torvalds 1319222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev->cur_in6_daddr, 1320222f1806SLuiz Capitulino &pkt_dev->min_in6_daddr); 13211da177e4SLinus Torvalds if (debug) 132225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf); 13231da177e4SLinus Torvalds 13241da177e4SLinus Torvalds i += len; 13251da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13261da177e4SLinus Torvalds return count; 13271da177e4SLinus Torvalds } 13281da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13291da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1330222f1806SLuiz Capitulino if (len < 0) 1331222f1806SLuiz Capitulino return len; 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13341da177e4SLinus Torvalds 13351da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13361da177e4SLinus Torvalds return -EFAULT; 13371da177e4SLinus Torvalds buf[len] = 0; 13381da177e4SLinus Torvalds 13391da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13401da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13411da177e4SLinus Torvalds 13421da177e4SLinus Torvalds if (debug) 134325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds i += len; 13461da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13471da177e4SLinus Torvalds return count; 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13501da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1351222f1806SLuiz Capitulino if (len < 0) 1352222f1806SLuiz Capitulino return len; 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13551da177e4SLinus Torvalds 13561da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13571da177e4SLinus Torvalds return -EFAULT; 13581da177e4SLinus Torvalds buf[len] = 0; 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13611da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds if (debug) 136625a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf); 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds i += len; 13691da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 13701da177e4SLinus Torvalds return count; 13711da177e4SLinus Torvalds } 13721da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 13731da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 1374222f1806SLuiz Capitulino if (len < 0) { 1375222f1806SLuiz Capitulino return len; 1376222f1806SLuiz Capitulino } 13771da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13781da177e4SLinus Torvalds return -EFAULT; 13791da177e4SLinus Torvalds buf[len] = 0; 13801da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 13811da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 13821da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 13831da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13841da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 13851da177e4SLinus Torvalds } 13861da177e4SLinus Torvalds if (debug) 138725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_min set to: %s\n", 1388222f1806SLuiz Capitulino pkt_dev->src_min); 13891da177e4SLinus Torvalds i += len; 13901da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 13911da177e4SLinus Torvalds return count; 13921da177e4SLinus Torvalds } 13931da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 13941da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 1395222f1806SLuiz Capitulino if (len < 0) { 1396222f1806SLuiz Capitulino return len; 1397222f1806SLuiz Capitulino } 13981da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13991da177e4SLinus Torvalds return -EFAULT; 14001da177e4SLinus Torvalds buf[len] = 0; 14011da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14021da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14031da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 14041da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14051da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14061da177e4SLinus Torvalds } 14071da177e4SLinus Torvalds if (debug) 140825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_max set to: %s\n", 1409222f1806SLuiz Capitulino pkt_dev->src_max); 14101da177e4SLinus Torvalds i += len; 14111da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14121da177e4SLinus Torvalds return count; 14131da177e4SLinus Torvalds } 14141da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14151da177e4SLinus Torvalds char *v = valstr; 1416f404e9a6SKris Katterjohn unsigned char old_dmac[ETH_ALEN]; 14171da177e4SLinus Torvalds unsigned char *m = pkt_dev->dst_mac; 1418f404e9a6SKris Katterjohn memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 1421222f1806SLuiz Capitulino if (len < 0) { 1422222f1806SLuiz Capitulino return len; 1423222f1806SLuiz Capitulino } 14241da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14251da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14261da177e4SLinus Torvalds return -EFAULT; 14271da177e4SLinus Torvalds i += len; 14281da177e4SLinus Torvalds 14291da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { 14301da177e4SLinus Torvalds if (*v >= '0' && *v <= '9') { 14311da177e4SLinus Torvalds *m *= 16; 14321da177e4SLinus Torvalds *m += *v - '0'; 14331da177e4SLinus Torvalds } 14341da177e4SLinus Torvalds if (*v >= 'A' && *v <= 'F') { 14351da177e4SLinus Torvalds *m *= 16; 14361da177e4SLinus Torvalds *m += *v - 'A' + 10; 14371da177e4SLinus Torvalds } 14381da177e4SLinus Torvalds if (*v >= 'a' && *v <= 'f') { 14391da177e4SLinus Torvalds *m *= 16; 14401da177e4SLinus Torvalds *m += *v - 'a' + 10; 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds if (*v == ':') { 14431da177e4SLinus Torvalds m++; 14441da177e4SLinus Torvalds *m = 0; 14451da177e4SLinus Torvalds } 14461da177e4SLinus Torvalds } 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds /* Set up Dest MAC */ 1449f404e9a6SKris Katterjohn if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) 1450f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds sprintf(pg_result, "OK: dstmac"); 14531da177e4SLinus Torvalds return count; 14541da177e4SLinus Torvalds } 14551da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14561da177e4SLinus Torvalds char *v = valstr; 1457*ce5d0b47SAdit Ranadive unsigned char old_smac[ETH_ALEN]; 14581da177e4SLinus Torvalds unsigned char *m = pkt_dev->src_mac; 14591da177e4SLinus Torvalds 1460*ce5d0b47SAdit Ranadive memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); 1461*ce5d0b47SAdit Ranadive 14621da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 1463222f1806SLuiz Capitulino if (len < 0) { 1464222f1806SLuiz Capitulino return len; 1465222f1806SLuiz Capitulino } 14661da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14671da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14681da177e4SLinus Torvalds return -EFAULT; 14691da177e4SLinus Torvalds i += len; 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { 14721da177e4SLinus Torvalds if (*v >= '0' && *v <= '9') { 14731da177e4SLinus Torvalds *m *= 16; 14741da177e4SLinus Torvalds *m += *v - '0'; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds if (*v >= 'A' && *v <= 'F') { 14771da177e4SLinus Torvalds *m *= 16; 14781da177e4SLinus Torvalds *m += *v - 'A' + 10; 14791da177e4SLinus Torvalds } 14801da177e4SLinus Torvalds if (*v >= 'a' && *v <= 'f') { 14811da177e4SLinus Torvalds *m *= 16; 14821da177e4SLinus Torvalds *m += *v - 'a' + 10; 14831da177e4SLinus Torvalds } 14841da177e4SLinus Torvalds if (*v == ':') { 14851da177e4SLinus Torvalds m++; 14861da177e4SLinus Torvalds *m = 0; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds } 14891da177e4SLinus Torvalds 1490*ce5d0b47SAdit Ranadive /* Set up Src MAC */ 1491*ce5d0b47SAdit Ranadive if (compare_ether_addr(old_smac, pkt_dev->src_mac)) 1492*ce5d0b47SAdit Ranadive memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); 1493*ce5d0b47SAdit Ranadive 14941da177e4SLinus Torvalds sprintf(pg_result, "OK: srcmac"); 14951da177e4SLinus Torvalds return count; 14961da177e4SLinus Torvalds } 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 14991da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 15001da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 15011da177e4SLinus Torvalds return count; 15021da177e4SLinus Torvalds } 15031da177e4SLinus Torvalds 15041da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 15051da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1506222f1806SLuiz Capitulino if (len < 0) { 1507222f1806SLuiz Capitulino return len; 1508222f1806SLuiz Capitulino } 15091da177e4SLinus Torvalds i += len; 15101da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15111da177e4SLinus Torvalds value = MAX_CFLOWS; 15121da177e4SLinus Torvalds 15131da177e4SLinus Torvalds pkt_dev->cflows = value; 15141da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15151da177e4SLinus Torvalds return count; 15161da177e4SLinus Torvalds } 15171da177e4SLinus Torvalds 15181da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15191da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 1520222f1806SLuiz Capitulino if (len < 0) { 1521222f1806SLuiz Capitulino return len; 1522222f1806SLuiz Capitulino } 15231da177e4SLinus Torvalds i += len; 15241da177e4SLinus Torvalds pkt_dev->lflow = value; 15251da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 15261da177e4SLinus Torvalds return count; 15271da177e4SLinus Torvalds } 15281da177e4SLinus Torvalds 1529ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 1530ca6549afSSteven Whitehouse unsigned n, offset; 1531ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1532ca6549afSSteven Whitehouse if (len < 0) { return len; } 1533ca6549afSSteven Whitehouse i += len; 1534ca6549afSSteven Whitehouse offset = sprintf(pg_result, "OK: mpls="); 1535ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1536ca6549afSSteven Whitehouse offset += sprintf(pg_result + offset, 1537ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1538ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 153934954ddcSFrancesco Fondelli 154034954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 154134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 154234954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 154334954ddcSFrancesco Fondelli 154434954ddcSFrancesco Fondelli if (debug) 154525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n"); 154634954ddcSFrancesco Fondelli } 154734954ddcSFrancesco Fondelli return count; 154834954ddcSFrancesco Fondelli } 154934954ddcSFrancesco Fondelli 155034954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 155134954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 155234954ddcSFrancesco Fondelli if (len < 0) { 155334954ddcSFrancesco Fondelli return len; 155434954ddcSFrancesco Fondelli } 155534954ddcSFrancesco Fondelli i += len; 155634954ddcSFrancesco Fondelli if (value <= 4095) { 155734954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 155834954ddcSFrancesco Fondelli 155934954ddcSFrancesco Fondelli if (debug) 156025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN turned on\n"); 156134954ddcSFrancesco Fondelli 156234954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 156325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 156434954ddcSFrancesco Fondelli 156534954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 156634954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 156734954ddcSFrancesco Fondelli } else { 156834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 156934954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 157034954ddcSFrancesco Fondelli 157134954ddcSFrancesco Fondelli if (debug) 157225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 157334954ddcSFrancesco Fondelli } 157434954ddcSFrancesco Fondelli return count; 157534954ddcSFrancesco Fondelli } 157634954ddcSFrancesco Fondelli 157734954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 157834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 157934954ddcSFrancesco Fondelli if (len < 0) { 158034954ddcSFrancesco Fondelli return len; 158134954ddcSFrancesco Fondelli } 158234954ddcSFrancesco Fondelli i += len; 158334954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 158434954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 158534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 158634954ddcSFrancesco Fondelli } else { 158734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 158834954ddcSFrancesco Fondelli } 158934954ddcSFrancesco Fondelli return count; 159034954ddcSFrancesco Fondelli } 159134954ddcSFrancesco Fondelli 159234954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 159334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 159434954ddcSFrancesco Fondelli if (len < 0) { 159534954ddcSFrancesco Fondelli return len; 159634954ddcSFrancesco Fondelli } 159734954ddcSFrancesco Fondelli i += len; 159834954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 159934954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 160034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 160134954ddcSFrancesco Fondelli } else { 160234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 160334954ddcSFrancesco Fondelli } 160434954ddcSFrancesco Fondelli return count; 160534954ddcSFrancesco Fondelli } 160634954ddcSFrancesco Fondelli 160734954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 160834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 160934954ddcSFrancesco Fondelli if (len < 0) { 161034954ddcSFrancesco Fondelli return len; 161134954ddcSFrancesco Fondelli } 161234954ddcSFrancesco Fondelli i += len; 161334954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 161434954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 161534954ddcSFrancesco Fondelli 161634954ddcSFrancesco Fondelli if (debug) 161725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: SVLAN turned on\n"); 161834954ddcSFrancesco Fondelli 161934954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 162025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 162134954ddcSFrancesco Fondelli 162234954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 162334954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 162434954ddcSFrancesco Fondelli } else { 162534954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 162634954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 162734954ddcSFrancesco Fondelli 162834954ddcSFrancesco Fondelli if (debug) 162925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 163034954ddcSFrancesco Fondelli } 163134954ddcSFrancesco Fondelli return count; 163234954ddcSFrancesco Fondelli } 163334954ddcSFrancesco Fondelli 163434954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 163534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 163634954ddcSFrancesco Fondelli if (len < 0) { 163734954ddcSFrancesco Fondelli return len; 163834954ddcSFrancesco Fondelli } 163934954ddcSFrancesco Fondelli i += len; 164034954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 164134954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 164234954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 164334954ddcSFrancesco Fondelli } else { 164434954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 164534954ddcSFrancesco Fondelli } 164634954ddcSFrancesco Fondelli return count; 164734954ddcSFrancesco Fondelli } 164834954ddcSFrancesco Fondelli 164934954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 165034954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 165134954ddcSFrancesco Fondelli if (len < 0) { 165234954ddcSFrancesco Fondelli return len; 165334954ddcSFrancesco Fondelli } 165434954ddcSFrancesco Fondelli i += len; 165534954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 165634954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 165734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 165834954ddcSFrancesco Fondelli } else { 165934954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 166034954ddcSFrancesco Fondelli } 1661ca6549afSSteven Whitehouse return count; 1662ca6549afSSteven Whitehouse } 1663ca6549afSSteven Whitehouse 16641ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16651ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16661ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 16671ca7768cSFrancesco Fondelli if (len < 0) { 16681ca7768cSFrancesco Fondelli return len; 16691ca7768cSFrancesco Fondelli } 16701ca7768cSFrancesco Fondelli i += len; 16711ca7768cSFrancesco Fondelli if (len == 2) { 16721ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16731ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16741ca7768cSFrancesco Fondelli } else { 16751ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 16761ca7768cSFrancesco Fondelli } 16771ca7768cSFrancesco Fondelli return count; 16781ca7768cSFrancesco Fondelli } 16791ca7768cSFrancesco Fondelli 16801ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 16811ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16821ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 16831ca7768cSFrancesco Fondelli if (len < 0) { 16841ca7768cSFrancesco Fondelli return len; 16851ca7768cSFrancesco Fondelli } 16861ca7768cSFrancesco Fondelli i += len; 16871ca7768cSFrancesco Fondelli if (len == 2) { 16881ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 16891ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 16901ca7768cSFrancesco Fondelli } else { 16911ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 16921ca7768cSFrancesco Fondelli } 16931ca7768cSFrancesco Fondelli return count; 16941ca7768cSFrancesco Fondelli } 16951ca7768cSFrancesco Fondelli 16961da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 16971da177e4SLinus Torvalds return -EINVAL; 16981da177e4SLinus Torvalds } 16991da177e4SLinus Torvalds 1700d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17011da177e4SLinus Torvalds { 1702d50a6b56SStephen Hemminger return single_open(file, pktgen_if_show, PDE(inode)->data); 17031da177e4SLinus Torvalds } 17041da177e4SLinus Torvalds 17059a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1706d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1707d50a6b56SStephen Hemminger .open = pktgen_if_open, 1708d50a6b56SStephen Hemminger .read = seq_read, 1709d50a6b56SStephen Hemminger .llseek = seq_lseek, 1710d50a6b56SStephen Hemminger .write = pktgen_if_write, 1711d50a6b56SStephen Hemminger .release = single_release, 1712d50a6b56SStephen Hemminger }; 1713d50a6b56SStephen Hemminger 1714d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1715d50a6b56SStephen Hemminger { 1716d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1717c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 1718d50a6b56SStephen Hemminger 1719d50a6b56SStephen Hemminger BUG_ON(!t); 1720d50a6b56SStephen Hemminger 1721d50a6b56SStephen Hemminger seq_printf(seq, "Name: %s max_before_softirq: %d\n", 1722ee74baa7SDavid S. Miller t->tsk->comm, t->max_before_softirq); 17231da177e4SLinus Torvalds 1724d50a6b56SStephen Hemminger seq_printf(seq, "Running: "); 17251da177e4SLinus Torvalds 17261da177e4SLinus Torvalds if_lock(t); 1727c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17281da177e4SLinus Torvalds if (pkt_dev->running) 172939df232fSStephen Hemminger seq_printf(seq, "%s ", pkt_dev->odev->name); 17301da177e4SLinus Torvalds 1731d50a6b56SStephen Hemminger seq_printf(seq, "\nStopped: "); 17321da177e4SLinus Torvalds 1733c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17341da177e4SLinus Torvalds if (!pkt_dev->running) 173539df232fSStephen Hemminger seq_printf(seq, "%s ", pkt_dev->odev->name); 17361da177e4SLinus Torvalds 17371da177e4SLinus Torvalds if (t->result[0]) 1738d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17391da177e4SLinus Torvalds else 1740d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: NA\n"); 17411da177e4SLinus Torvalds 17421da177e4SLinus Torvalds if_unlock(t); 17431da177e4SLinus Torvalds 1744d50a6b56SStephen Hemminger return 0; 17451da177e4SLinus Torvalds } 17461da177e4SLinus Torvalds 1747d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1748d50a6b56SStephen Hemminger const char __user * user_buffer, 1749d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17501da177e4SLinus Torvalds { 1751d50a6b56SStephen Hemminger struct seq_file *seq = (struct seq_file *)file->private_data; 1752d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 17531da177e4SLinus Torvalds int i = 0, max, len, ret; 17541da177e4SLinus Torvalds char name[40]; 17551da177e4SLinus Torvalds char *pg_result; 17561da177e4SLinus Torvalds unsigned long value = 0; 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds if (count < 1) { 17591da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17601da177e4SLinus Torvalds return -EINVAL; 17611da177e4SLinus Torvalds } 17621da177e4SLinus Torvalds 17631da177e4SLinus Torvalds max = count - i; 17641da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 17651da177e4SLinus Torvalds if (len < 0) 17661da177e4SLinus Torvalds return len; 17671da177e4SLinus Torvalds 17681da177e4SLinus Torvalds i += len; 17691da177e4SLinus Torvalds 17701da177e4SLinus Torvalds /* Read variable name */ 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 17731da177e4SLinus Torvalds if (len < 0) 17741da177e4SLinus Torvalds return len; 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 17771da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 17781da177e4SLinus Torvalds return -EFAULT; 17791da177e4SLinus Torvalds i += len; 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds max = count - i; 17821da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 17831da177e4SLinus Torvalds if (len < 0) 17841da177e4SLinus Torvalds return len; 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds i += len; 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds if (debug) 178925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n", 179025a8b254SDavid S. Miller name, (unsigned long)count); 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds if (!t) { 179325a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: No thread\n"); 17941da177e4SLinus Torvalds ret = -EINVAL; 17951da177e4SLinus Torvalds goto out; 17961da177e4SLinus Torvalds } 17971da177e4SLinus Torvalds 17981da177e4SLinus Torvalds pg_result = &(t->result[0]); 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 18011da177e4SLinus Torvalds char f[32]; 18021da177e4SLinus Torvalds memset(f, 0, 32); 18031da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18041da177e4SLinus Torvalds if (len < 0) { 18051da177e4SLinus Torvalds ret = len; 18061da177e4SLinus Torvalds goto out; 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18091da177e4SLinus Torvalds return -EFAULT; 18101da177e4SLinus Torvalds i += len; 18116146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 18121da177e4SLinus Torvalds pktgen_add_device(t, f); 18136146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 18141da177e4SLinus Torvalds ret = count; 18151da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 18161da177e4SLinus Torvalds goto out; 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18206146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 182195ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18226146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1823121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18241da177e4SLinus Torvalds ret = count; 18251da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18261da177e4SLinus Torvalds goto out; 18271da177e4SLinus Torvalds } 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 18301da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 18316146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 18321da177e4SLinus Torvalds t->max_before_softirq = value; 18336146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 18341da177e4SLinus Torvalds ret = count; 18351da177e4SLinus Torvalds sprintf(pg_result, "OK: max_before_softirq=%lu", value); 18361da177e4SLinus Torvalds goto out; 18371da177e4SLinus Torvalds } 18381da177e4SLinus Torvalds 18391da177e4SLinus Torvalds ret = -EINVAL; 18401da177e4SLinus Torvalds out: 18411da177e4SLinus Torvalds return ret; 18421da177e4SLinus Torvalds } 18431da177e4SLinus Torvalds 1844d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18451da177e4SLinus Torvalds { 1846d50a6b56SStephen Hemminger return single_open(file, pktgen_thread_show, PDE(inode)->data); 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds 18499a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1850d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1851d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1852d50a6b56SStephen Hemminger .read = seq_read, 1853d50a6b56SStephen Hemminger .llseek = seq_lseek, 1854d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1855d50a6b56SStephen Hemminger .release = single_release, 1856d50a6b56SStephen Hemminger }; 18571da177e4SLinus Torvalds 18581da177e4SLinus Torvalds /* Think find or remove for NN */ 18591da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) 18601da177e4SLinus Torvalds { 18611da177e4SLinus Torvalds struct pktgen_thread *t; 18621da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18631da177e4SLinus Torvalds 1864cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 18651da177e4SLinus Torvalds pkt_dev = pktgen_find_dev(t, ifname); 18661da177e4SLinus Torvalds if (pkt_dev) { 18671da177e4SLinus Torvalds if (remove) { 18681da177e4SLinus Torvalds if_lock(t); 186995ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 187095ed63f7SArthur Kepner t->control |= T_REMDEV; 18711da177e4SLinus Torvalds if_unlock(t); 18721da177e4SLinus Torvalds } 18731da177e4SLinus Torvalds break; 18741da177e4SLinus Torvalds } 18751da177e4SLinus Torvalds } 18761da177e4SLinus Torvalds return pkt_dev; 18771da177e4SLinus Torvalds } 18781da177e4SLinus Torvalds 187995ed63f7SArthur Kepner /* 188095ed63f7SArthur Kepner * mark a device for removal 188195ed63f7SArthur Kepner */ 188239df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname) 18831da177e4SLinus Torvalds { 18841da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 188595ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 188695ed63f7SArthur Kepner int i = 0; 188795ed63f7SArthur Kepner 18886146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 188925c4e53aSStephen Hemminger pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname); 189095ed63f7SArthur Kepner 189195ed63f7SArthur Kepner while (1) { 189295ed63f7SArthur Kepner 189395ed63f7SArthur Kepner pkt_dev = __pktgen_NN_threads(ifname, REMOVE); 1894222f1806SLuiz Capitulino if (pkt_dev == NULL) 1895222f1806SLuiz Capitulino break; /* success */ 189695ed63f7SArthur Kepner 18976146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 189825c4e53aSStephen Hemminger pr_debug("pktgen: pktgen_mark_device waiting for %s " 189925c4e53aSStephen Hemminger "to disappear....\n", ifname); 190095ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 19016146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 190295ed63f7SArthur Kepner 190395ed63f7SArthur Kepner if (++i >= max_tries) { 190425a8b254SDavid S. Miller printk(KERN_ERR "pktgen_mark_device: timed out after " 190525a8b254SDavid S. Miller "waiting %d msec for device %s to be removed\n", 190695ed63f7SArthur Kepner msec_per_try * i, ifname); 190795ed63f7SArthur Kepner break; 190895ed63f7SArthur Kepner } 190995ed63f7SArthur Kepner 191095ed63f7SArthur Kepner } 191195ed63f7SArthur Kepner 19126146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 191339df232fSStephen Hemminger } 191495ed63f7SArthur Kepner 191539df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev) 191639df232fSStephen Hemminger { 191739df232fSStephen Hemminger struct pktgen_thread *t; 191839df232fSStephen Hemminger 191939df232fSStephen Hemminger list_for_each_entry(t, &pktgen_threads, th_list) { 192039df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 192139df232fSStephen Hemminger 192239df232fSStephen Hemminger list_for_each_entry(pkt_dev, &t->if_list, list) { 192339df232fSStephen Hemminger if (pkt_dev->odev != dev) 192439df232fSStephen Hemminger continue; 192539df232fSStephen Hemminger 192639df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 192739df232fSStephen Hemminger 192839df232fSStephen Hemminger pkt_dev->entry = create_proc_entry(dev->name, 0600, 192939df232fSStephen Hemminger pg_proc_dir); 193039df232fSStephen Hemminger if (!pkt_dev->entry) 193139df232fSStephen Hemminger printk(KERN_ERR "pktgen: can't move proc " 193239df232fSStephen Hemminger " entry for '%s'\n", dev->name); 193339df232fSStephen Hemminger break; 193439df232fSStephen Hemminger } 193539df232fSStephen Hemminger } 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 1938222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1939222f1806SLuiz Capitulino unsigned long event, void *ptr) 19401da177e4SLinus Torvalds { 194139df232fSStephen Hemminger struct net_device *dev = ptr; 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19441da177e4SLinus Torvalds * as we run under the RTNL lock. 19451da177e4SLinus Torvalds */ 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds switch (event) { 194839df232fSStephen Hemminger case NETDEV_CHANGENAME: 194939df232fSStephen Hemminger pktgen_change_name(dev); 19501da177e4SLinus Torvalds break; 19511da177e4SLinus Torvalds 19521da177e4SLinus Torvalds case NETDEV_UNREGISTER: 195395ed63f7SArthur Kepner pktgen_mark_device(dev->name); 19541da177e4SLinus Torvalds break; 19553ff50b79SStephen Hemminger } 19561da177e4SLinus Torvalds 19571da177e4SLinus Torvalds return NOTIFY_DONE; 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 19611da177e4SLinus Torvalds 196239df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) 1963222f1806SLuiz Capitulino { 19641da177e4SLinus Torvalds struct net_device *odev; 196539df232fSStephen Hemminger int err; 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds /* Clean old setups */ 19681da177e4SLinus Torvalds if (pkt_dev->odev) { 19691da177e4SLinus Torvalds dev_put(pkt_dev->odev); 19701da177e4SLinus Torvalds pkt_dev->odev = NULL; 19711da177e4SLinus Torvalds } 19721da177e4SLinus Torvalds 197339df232fSStephen Hemminger odev = dev_get_by_name(ifname); 19741da177e4SLinus Torvalds if (!odev) { 197525a8b254SDavid S. Miller printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname); 197639df232fSStephen Hemminger return -ENODEV; 19771da177e4SLinus Torvalds } 197839df232fSStephen Hemminger 19791da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 198025a8b254SDavid S. Miller printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname); 198139df232fSStephen Hemminger err = -EINVAL; 198239df232fSStephen Hemminger } else if (!netif_running(odev)) { 198325a8b254SDavid S. Miller printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname); 198439df232fSStephen Hemminger err = -ENETDOWN; 198539df232fSStephen Hemminger } else { 19861da177e4SLinus Torvalds pkt_dev->odev = odev; 198739df232fSStephen Hemminger return 0; 198839df232fSStephen Hemminger } 19891da177e4SLinus Torvalds 19901da177e4SLinus Torvalds dev_put(odev); 199139df232fSStephen Hemminger return err; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 19951da177e4SLinus Torvalds * structure to have the right information to create/send packets 19961da177e4SLinus Torvalds */ 19971da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 19981da177e4SLinus Torvalds { 19991da177e4SLinus Torvalds if (!pkt_dev->odev) { 200025a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in " 200125a8b254SDavid S. Miller "setup_inject.\n"); 2002222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2003222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20041da177e4SLinus Torvalds return; 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 20071da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20081da177e4SLinus Torvalds 2009f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 2010f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); 20111da177e4SLinus Torvalds 20121da177e4SLinus Torvalds /* Set up Dest MAC */ 2013f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 20141da177e4SLinus Torvalds 20151da177e4SLinus Torvalds /* Set up pkt size */ 20161da177e4SLinus Torvalds pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20191da177e4SLinus Torvalds /* 20201da177e4SLinus Torvalds * Skip this automatic address setting until locks or functions 20211da177e4SLinus Torvalds * gets exported 20221da177e4SLinus Torvalds */ 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds #ifdef NOTNOW 20251da177e4SLinus Torvalds int i, set = 0, err = 1; 20261da177e4SLinus Torvalds struct inet6_dev *idev; 20271da177e4SLinus Torvalds 20281da177e4SLinus Torvalds for (i = 0; i < IN6_ADDR_HSIZE; i++) 20291da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20301da177e4SLinus Torvalds set = 1; 20311da177e4SLinus Torvalds break; 20321da177e4SLinus Torvalds } 20331da177e4SLinus Torvalds 20341da177e4SLinus Torvalds if (!set) { 20351da177e4SLinus Torvalds 20361da177e4SLinus Torvalds /* 20371da177e4SLinus Torvalds * Use linklevel address if unconfigured. 20381da177e4SLinus Torvalds * 20391da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 20401da177e4SLinus Torvalds */ 20411da177e4SLinus Torvalds 20428814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 20431da177e4SLinus Torvalds if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { 20441da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 20451da177e4SLinus Torvalds 20461da177e4SLinus Torvalds read_lock_bh(&idev->lock); 2047222f1806SLuiz Capitulino for (ifp = idev->addr_list; ifp; 2048222f1806SLuiz Capitulino ifp = ifp->if_next) { 2049222f1806SLuiz Capitulino if (ifp->scope == IFA_LINK 2050222f1806SLuiz Capitulino && !(ifp-> 2051222f1806SLuiz Capitulino flags & IFA_F_TENTATIVE)) { 2052222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev-> 2053222f1806SLuiz Capitulino cur_in6_saddr, 2054222f1806SLuiz Capitulino &ifp->addr); 20551da177e4SLinus Torvalds err = 0; 20561da177e4SLinus Torvalds break; 20571da177e4SLinus Torvalds } 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 20601da177e4SLinus Torvalds } 20618814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2062222f1806SLuiz Capitulino if (err) 206325a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: IPv6 link " 206425a8b254SDavid S. Miller "address not availble.\n"); 20651da177e4SLinus Torvalds } 20661da177e4SLinus Torvalds #endif 2067222f1806SLuiz Capitulino } else { 20681da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 20691da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 20701da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 20711da177e4SLinus Torvalds 20721da177e4SLinus Torvalds struct in_device *in_dev; 20731da177e4SLinus Torvalds 20741da177e4SLinus Torvalds rcu_read_lock(); 2075e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 20761da177e4SLinus Torvalds if (in_dev) { 20771da177e4SLinus Torvalds if (in_dev->ifa_list) { 2078222f1806SLuiz Capitulino pkt_dev->saddr_min = 2079222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 20801da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 20811da177e4SLinus Torvalds } 20821da177e4SLinus Torvalds } 20831da177e4SLinus Torvalds rcu_read_unlock(); 2084222f1806SLuiz Capitulino } else { 20851da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 20861da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 20871da177e4SLinus Torvalds } 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 20901da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 20911da177e4SLinus Torvalds } 20921da177e4SLinus Torvalds /* Initialize current values. */ 20931da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 20941da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 20951da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 20961da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 20971da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 20981da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 20991da177e4SLinus Torvalds pkt_dev->nflows = 0; 21001da177e4SLinus Torvalds } 21011da177e4SLinus Torvalds 21021da177e4SLinus Torvalds static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) 21031da177e4SLinus Torvalds { 21041da177e4SLinus Torvalds __u64 start; 21051da177e4SLinus Torvalds __u64 now; 21061da177e4SLinus Torvalds 21071da177e4SLinus Torvalds start = now = getCurUs(); 21081da177e4SLinus Torvalds printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now)); 21091da177e4SLinus Torvalds while (now < spin_until_us) { 2110b4099fabSStephen Hemminger /* TODO: optimize sleeping behavior */ 2111121caf57SNishanth Aravamudan if (spin_until_us - now > jiffies_to_usecs(1) + 1) 2112121caf57SNishanth Aravamudan schedule_timeout_interruptible(1); 2113121caf57SNishanth Aravamudan else if (spin_until_us - now > 100) { 21141da177e4SLinus Torvalds do_softirq(); 21151da177e4SLinus Torvalds if (!pkt_dev->running) 21161da177e4SLinus Torvalds return; 21171da177e4SLinus Torvalds if (need_resched()) 21181da177e4SLinus Torvalds schedule(); 21191da177e4SLinus Torvalds } 21201da177e4SLinus Torvalds 21211da177e4SLinus Torvalds now = getCurUs(); 21221da177e4SLinus Torvalds } 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds pkt_dev->idle_acc += now - start; 21251da177e4SLinus Torvalds } 21261da177e4SLinus Torvalds 212716dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 212816dab72fSJamal Hadi Salim { 2129a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead = 0; 213016dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 213116dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 213216dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 213316dab72fSJamal Hadi Salim } 213416dab72fSJamal Hadi Salim 2135007a531bSJamal Hadi Salim static inline int f_seen(struct pktgen_dev *pkt_dev, int flow) 2136007a531bSJamal Hadi Salim { 2137007a531bSJamal Hadi Salim 2138007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].flags & F_INIT) 2139007a531bSJamal Hadi Salim return 1; 2140007a531bSJamal Hadi Salim else 2141007a531bSJamal Hadi Salim return 0; 2142007a531bSJamal Hadi Salim } 2143007a531bSJamal Hadi Salim 2144007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2145007a531bSJamal Hadi Salim { 2146007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2147007a531bSJamal Hadi Salim 2148007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2149007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2150007a531bSJamal Hadi Salim /* reset time */ 2151007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 2152007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2153007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2154007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2155007a531bSJamal Hadi Salim } 2156007a531bSJamal Hadi Salim } else { 2157007a531bSJamal Hadi Salim flow = random32() % pkt_dev->cflows; 2158007a531bSJamal Hadi Salim 2159007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count > pkt_dev->lflow) 2160007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 2161007a531bSJamal Hadi Salim } 2162007a531bSJamal Hadi Salim 2163007a531bSJamal Hadi Salim return pkt_dev->curfl; 2164007a531bSJamal Hadi Salim } 2165007a531bSJamal Hadi Salim 2166a553e4a6SJamal Hadi Salim 2167a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2168a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2169a553e4a6SJamal Hadi Salim * we go look for it ... 2170a553e4a6SJamal Hadi Salim */ 2171fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2172a553e4a6SJamal Hadi Salim { 2173a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 2174a553e4a6SJamal Hadi Salim if (!x) { 2175a553e4a6SJamal Hadi Salim /*slow path: we dont already have xfrm_state*/ 2176a553e4a6SJamal Hadi Salim x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr, 2177a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2178a553e4a6SJamal Hadi Salim AF_INET, 2179a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2180a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2181a553e4a6SJamal Hadi Salim if (x) { 2182a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2183a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2184a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead+=x->props.header_len; 2185a553e4a6SJamal Hadi Salim } 2186a553e4a6SJamal Hadi Salim 2187a553e4a6SJamal Hadi Salim } 2188a553e4a6SJamal Hadi Salim } 2189a553e4a6SJamal Hadi Salim #endif 21901da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 21911da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 21921da177e4SLinus Torvalds */ 2193222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2194222f1806SLuiz Capitulino { 21951da177e4SLinus Torvalds __u32 imn; 21961da177e4SLinus Torvalds __u32 imx; 21971da177e4SLinus Torvalds int flow = 0; 21981da177e4SLinus Torvalds 2199007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2200007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds /* Deal with source MAC */ 22031da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 22041da177e4SLinus Torvalds __u32 mc; 22051da177e4SLinus Torvalds __u32 tmp; 22061da177e4SLinus Torvalds 22071da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 22085fa6fc76SStephen Hemminger mc = random32() % pkt_dev->src_mac_count; 22091da177e4SLinus Torvalds else { 22101da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2211222f1806SLuiz Capitulino if (pkt_dev->cur_src_mac_offset > 2212222f1806SLuiz Capitulino pkt_dev->src_mac_count) 22131da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 22141da177e4SLinus Torvalds } 22151da177e4SLinus Torvalds 22161da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 22171da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 22181da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 22191da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 22201da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 22211da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 22221da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 22231da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 22241da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 22251da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 22261da177e4SLinus Torvalds } 22271da177e4SLinus Torvalds 22281da177e4SLinus Torvalds /* Deal with Destination MAC */ 22291da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 22301da177e4SLinus Torvalds __u32 mc; 22311da177e4SLinus Torvalds __u32 tmp; 22321da177e4SLinus Torvalds 22331da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 22345fa6fc76SStephen Hemminger mc = random32() % pkt_dev->dst_mac_count; 22351da177e4SLinus Torvalds 22361da177e4SLinus Torvalds else { 22371da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2238222f1806SLuiz Capitulino if (pkt_dev->cur_dst_mac_offset > 2239222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 22401da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 22411da177e4SLinus Torvalds } 22421da177e4SLinus Torvalds } 22431da177e4SLinus Torvalds 22441da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 22451da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 22461da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 22471da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 22481da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 22491da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 22501da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 22511da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 22521da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 22531da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 22541da177e4SLinus Torvalds } 22551da177e4SLinus Torvalds 2256ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 2257ca6549afSSteven Whitehouse unsigned i; 2258ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2259ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2260ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 22615fa6fc76SStephen Hemminger ((__force __be32)random32() & 2262ca6549afSSteven Whitehouse htonl(0x000fffff)); 2263ca6549afSSteven Whitehouse } 2264ca6549afSSteven Whitehouse 226534954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 22665fa6fc76SStephen Hemminger pkt_dev->vlan_id = random32() & (4096-1); 226734954ddcSFrancesco Fondelli } 226834954ddcSFrancesco Fondelli 226934954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 22705fa6fc76SStephen Hemminger pkt_dev->svlan_id = random32() & (4096 - 1); 227134954ddcSFrancesco Fondelli } 227234954ddcSFrancesco Fondelli 22731da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 22741da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 22755fa6fc76SStephen Hemminger pkt_dev->cur_udp_src = random32() % 22765fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 22775fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 22781da177e4SLinus Torvalds 22791da177e4SLinus Torvalds else { 22801da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 22811da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 22821da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 22831da177e4SLinus Torvalds } 22841da177e4SLinus Torvalds } 22851da177e4SLinus Torvalds 22861da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 22871da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 22885fa6fc76SStephen Hemminger pkt_dev->cur_udp_dst = random32() % 22895fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 22905fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2291222f1806SLuiz Capitulino } else { 22921da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 22931da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 22941da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 22951da177e4SLinus Torvalds } 22961da177e4SLinus Torvalds } 22971da177e4SLinus Torvalds 22981da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 22991da177e4SLinus Torvalds 2300222f1806SLuiz Capitulino if ((imn = ntohl(pkt_dev->saddr_min)) < (imx = 2301222f1806SLuiz Capitulino ntohl(pkt_dev-> 2302222f1806SLuiz Capitulino saddr_max))) { 23031da177e4SLinus Torvalds __u32 t; 23041da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 23055fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 23061da177e4SLinus Torvalds else { 23071da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 23081da177e4SLinus Torvalds t++; 23091da177e4SLinus Torvalds if (t > imx) { 23101da177e4SLinus Torvalds t = imn; 23111da177e4SLinus Torvalds } 23121da177e4SLinus Torvalds } 23131da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 23141da177e4SLinus Torvalds } 23151da177e4SLinus Torvalds 2316007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 23171da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 23181da177e4SLinus Torvalds } else { 2319252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2320252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2321252e3346SAl Viro if (imn < imx) { 23221da177e4SLinus Torvalds __u32 t; 2323252e3346SAl Viro __be32 s; 23241da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 23251da177e4SLinus Torvalds 23265fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2327252e3346SAl Viro s = htonl(t); 23281da177e4SLinus Torvalds 2329252e3346SAl Viro while (LOOPBACK(s) || MULTICAST(s) 2330252e3346SAl Viro || BADCLASS(s) || ZERONET(s) 2331252e3346SAl Viro || LOCAL_MCAST(s)) { 23325fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2333252e3346SAl Viro s = htonl(t); 23341da177e4SLinus Torvalds } 2335252e3346SAl Viro pkt_dev->cur_daddr = s; 2336252e3346SAl Viro } else { 23371da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 23381da177e4SLinus Torvalds t++; 23391da177e4SLinus Torvalds if (t > imx) { 23401da177e4SLinus Torvalds t = imn; 23411da177e4SLinus Torvalds } 23421da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 23431da177e4SLinus Torvalds } 23441da177e4SLinus Torvalds } 23451da177e4SLinus Torvalds if (pkt_dev->cflows) { 2346007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2347222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2348222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2349a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2350a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 2351a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2352a553e4a6SJamal Hadi Salim #endif 23531da177e4SLinus Torvalds pkt_dev->nflows++; 23541da177e4SLinus Torvalds } 23551da177e4SLinus Torvalds } 2356222f1806SLuiz Capitulino } else { /* IPV6 * */ 2357222f1806SLuiz Capitulino 23581da177e4SLinus Torvalds if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && 23591da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && 23601da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && 23611da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ; 23621da177e4SLinus Torvalds else { 23631da177e4SLinus Torvalds int i; 23641da177e4SLinus Torvalds 23651da177e4SLinus Torvalds /* Only random destinations yet */ 23661da177e4SLinus Torvalds 23671da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 23681da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 23695fa6fc76SStephen Hemminger (((__force __be32)random32() | 23701da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 23711da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds 23761da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 23771da177e4SLinus Torvalds __u32 t; 23781da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 23795fa6fc76SStephen Hemminger t = random32() % 23805fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 23815fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2382222f1806SLuiz Capitulino } else { 23831da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 23841da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 23851da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 23861da177e4SLinus Torvalds } 23871da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 23881da177e4SLinus Torvalds } 23891da177e4SLinus Torvalds 23901da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds 2393a553e4a6SJamal Hadi Salim 2394a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2395a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2396a553e4a6SJamal Hadi Salim { 2397a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2398a553e4a6SJamal Hadi Salim int err = 0; 2399a553e4a6SJamal Hadi Salim struct iphdr *iph; 2400a553e4a6SJamal Hadi Salim 2401a553e4a6SJamal Hadi Salim if (!x) 2402a553e4a6SJamal Hadi Salim return 0; 2403a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2404a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2405a553e4a6SJamal Hadi Salim if (x->props.mode != XFRM_MODE_TRANSPORT) 2406a553e4a6SJamal Hadi Salim return 0; 2407a553e4a6SJamal Hadi Salim 2408a553e4a6SJamal Hadi Salim spin_lock(&x->lock); 2409a553e4a6SJamal Hadi Salim iph = ip_hdr(skb); 2410a553e4a6SJamal Hadi Salim 2411a553e4a6SJamal Hadi Salim err = x->mode->output(x, skb); 2412a553e4a6SJamal Hadi Salim if (err) 2413a553e4a6SJamal Hadi Salim goto error; 2414a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 2415a553e4a6SJamal Hadi Salim if (err) 2416a553e4a6SJamal Hadi Salim goto error; 2417a553e4a6SJamal Hadi Salim 2418a553e4a6SJamal Hadi Salim x->curlft.bytes +=skb->len; 2419a553e4a6SJamal Hadi Salim x->curlft.packets++; 2420a553e4a6SJamal Hadi Salim spin_unlock(&x->lock); 2421a553e4a6SJamal Hadi Salim 2422a553e4a6SJamal Hadi Salim error: 2423a553e4a6SJamal Hadi Salim spin_unlock(&x->lock); 2424a553e4a6SJamal Hadi Salim return err; 2425a553e4a6SJamal Hadi Salim } 2426a553e4a6SJamal Hadi Salim 2427a553e4a6SJamal Hadi Salim static inline void free_SAs(struct pktgen_dev *pkt_dev) 2428a553e4a6SJamal Hadi Salim { 2429a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2430a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2431a553e4a6SJamal Hadi Salim int i = 0; 2432a553e4a6SJamal Hadi Salim for (; i < pkt_dev->nflows; i++){ 2433a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2434a553e4a6SJamal Hadi Salim if (x) { 2435a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2436a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2437a553e4a6SJamal Hadi Salim } 2438a553e4a6SJamal Hadi Salim } 2439a553e4a6SJamal Hadi Salim } 2440a553e4a6SJamal Hadi Salim } 2441a553e4a6SJamal Hadi Salim 2442a553e4a6SJamal Hadi Salim static inline int process_ipsec(struct pktgen_dev *pkt_dev, 2443a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2444a553e4a6SJamal Hadi Salim { 2445a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) { 2446a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2447a553e4a6SJamal Hadi Salim int nhead = 0; 2448a553e4a6SJamal Hadi Salim if (x) { 2449a553e4a6SJamal Hadi Salim int ret; 2450a553e4a6SJamal Hadi Salim __u8 *eth; 2451a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2452a553e4a6SJamal Hadi Salim if (nhead >0) { 2453a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2454a553e4a6SJamal Hadi Salim if (ret < 0) { 245525a8b254SDavid S. Miller printk(KERN_ERR "Error expanding " 245625a8b254SDavid S. Miller "ipsec packet %d\n",ret); 2457a553e4a6SJamal Hadi Salim return 0; 2458a553e4a6SJamal Hadi Salim } 2459a553e4a6SJamal Hadi Salim } 2460a553e4a6SJamal Hadi Salim 2461a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2462a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2463a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2464a553e4a6SJamal Hadi Salim if (ret) { 246525a8b254SDavid S. Miller printk(KERN_ERR "Error creating ipsec " 246625a8b254SDavid S. Miller "packet %d\n",ret); 2467a553e4a6SJamal Hadi Salim kfree_skb(skb); 2468a553e4a6SJamal Hadi Salim return 0; 2469a553e4a6SJamal Hadi Salim } 2470a553e4a6SJamal Hadi Salim /* restore ll */ 2471a553e4a6SJamal Hadi Salim eth = (__u8 *) skb_push(skb, ETH_HLEN); 2472a553e4a6SJamal Hadi Salim memcpy(eth, pkt_dev->hh, 12); 2473a553e4a6SJamal Hadi Salim *(u16 *) & eth[12] = protocol; 2474a553e4a6SJamal Hadi Salim } 2475a553e4a6SJamal Hadi Salim } 2476a553e4a6SJamal Hadi Salim return 1; 2477a553e4a6SJamal Hadi Salim } 2478a553e4a6SJamal Hadi Salim #endif 2479a553e4a6SJamal Hadi Salim 2480ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2481ca6549afSSteven Whitehouse { 2482ca6549afSSteven Whitehouse unsigned i; 2483ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) { 2484ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 2485ca6549afSSteven Whitehouse } 2486ca6549afSSteven Whitehouse mpls--; 2487ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2488ca6549afSSteven Whitehouse } 2489ca6549afSSteven Whitehouse 24900f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 24910f37c605SAl Viro unsigned int prio) 24920f37c605SAl Viro { 24930f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 24940f37c605SAl Viro } 24950f37c605SAl Viro 24961da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 24971da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 24981da177e4SLinus Torvalds { 24991da177e4SLinus Torvalds struct sk_buff *skb = NULL; 25001da177e4SLinus Torvalds __u8 *eth; 25011da177e4SLinus Torvalds struct udphdr *udph; 25021da177e4SLinus Torvalds int datalen, iplen; 25031da177e4SLinus Torvalds struct iphdr *iph; 25041da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2505d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2506ca6549afSSteven Whitehouse __be32 *mpls; 250734954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 250834954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 250934954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 251034954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 251134954ddcSFrancesco Fondelli 2512ca6549afSSteven Whitehouse 2513ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2514d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 25151da177e4SLinus Torvalds 251634954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2517d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 251834954ddcSFrancesco Fondelli 251964053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 252064053beeSRobert Olsson * fields. 252164053beeSRobert Olsson */ 252264053beeSRobert Olsson mod_cur_headers(pkt_dev); 252364053beeSRobert Olsson 25247ac5459eSDavid S. Miller datalen = (odev->hard_header_len + 16) & ~0xf; 2525ca6549afSSteven Whitehouse skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + 252616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead, GFP_ATOMIC); 25271da177e4SLinus Torvalds if (!skb) { 25281da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 25291da177e4SLinus Torvalds return NULL; 25301da177e4SLinus Torvalds } 25311da177e4SLinus Torvalds 25327ac5459eSDavid S. Miller skb_reserve(skb, datalen); 25331da177e4SLinus Torvalds 25341da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 25351da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2536ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2537ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2538ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 253934954ddcSFrancesco Fondelli 254034954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 254134954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 254234954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 25430f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 25440f37c605SAl Viro pkt_dev->svlan_cfi, 25450f37c605SAl Viro pkt_dev->svlan_p); 254634954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2547d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 254834954ddcSFrancesco Fondelli } 254934954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 25500f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 25510f37c605SAl Viro pkt_dev->vlan_cfi, 25520f37c605SAl Viro pkt_dev->vlan_p); 255334954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2554d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 255534954ddcSFrancesco Fondelli } 255634954ddcSFrancesco Fondelli 255727a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 2558b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct iphdr); 2559ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); 2560ddc7b8e3SArnaldo Carvalho de Melo 2561ddc7b8e3SArnaldo Carvalho de Melo iph = ip_hdr(skb); 2562ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 25631da177e4SLinus Torvalds 25641da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2565252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 25661da177e4SLinus Torvalds 2567ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2568ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 256916dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 25701da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) 25711da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 25721da177e4SLinus Torvalds 25731da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 25741da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 25751da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 25761da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 25771da177e4SLinus Torvalds 25781da177e4SLinus Torvalds iph->ihl = 5; 25791da177e4SLinus Torvalds iph->version = 4; 25801da177e4SLinus Torvalds iph->ttl = 32; 25811ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 25821da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 25831da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 25841da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 25851da177e4SLinus Torvalds iph->frag_off = 0; 25861da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 25871da177e4SLinus Torvalds iph->tot_len = htons(iplen); 25881da177e4SLinus Torvalds iph->check = 0; 25891da177e4SLinus Torvalds iph->check = ip_fast_csum((void *)iph, iph->ihl); 2590ca6549afSSteven Whitehouse skb->protocol = protocol; 2591b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 259216dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 25931da177e4SLinus Torvalds skb->dev = odev; 25941da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 25951da177e4SLinus Torvalds 25961da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 25971da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 25981da177e4SLinus Torvalds else { 25991da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 26001da177e4SLinus Torvalds int i; 26011da177e4SLinus Torvalds 26021da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 26031da177e4SLinus Torvalds 26041da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 26051da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 26061da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 26071da177e4SLinus Torvalds skb_put(skb, datalen - frags * PAGE_SIZE); 26081da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 26091da177e4SLinus Torvalds } 26101da177e4SLinus Torvalds 26111da177e4SLinus Torvalds i = 0; 26121da177e4SLinus Torvalds while (datalen > 0) { 26131da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 26141da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 26151da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 26161da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 26171da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 26181da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 26191da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 26201da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 26211da177e4SLinus Torvalds i++; 26221da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 26231da177e4SLinus Torvalds } 26241da177e4SLinus Torvalds 26251da177e4SLinus Torvalds while (i < frags) { 26261da177e4SLinus Torvalds int rem; 26271da177e4SLinus Torvalds 26281da177e4SLinus Torvalds if (i == 0) 26291da177e4SLinus Torvalds break; 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 26321da177e4SLinus Torvalds if (rem == 0) 26331da177e4SLinus Torvalds break; 26341da177e4SLinus Torvalds 26351da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 26361da177e4SLinus Torvalds 2637222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 2638222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 26391da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2640222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 2641222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 2642222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 2643222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 26441da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 26451da177e4SLinus Torvalds i++; 26461da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 26471da177e4SLinus Torvalds } 26481da177e4SLinus Torvalds } 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds /* Stamp the time, and sequence number, convert them to network byte order */ 26511da177e4SLinus Torvalds 26521da177e4SLinus Torvalds if (pgh) { 26531da177e4SLinus Torvalds struct timeval timestamp; 26541da177e4SLinus Torvalds 26551da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 26561da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 26571da177e4SLinus Torvalds 26581da177e4SLinus Torvalds do_gettimeofday(×tamp); 26591da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 26601da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 26611da177e4SLinus Torvalds } 26621da177e4SLinus Torvalds 2663a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2664a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2665a553e4a6SJamal Hadi Salim return NULL; 2666a553e4a6SJamal Hadi Salim #endif 2667a553e4a6SJamal Hadi Salim 26681da177e4SLinus Torvalds return skb; 26691da177e4SLinus Torvalds } 26701da177e4SLinus Torvalds 26711da177e4SLinus Torvalds /* 26721da177e4SLinus Torvalds * scan_ip6, fmt_ip taken from dietlibc-0.21 26731da177e4SLinus Torvalds * Author Felix von Leitner <felix-dietlibc@fefe.de> 26741da177e4SLinus Torvalds * 26751da177e4SLinus Torvalds * Slightly modified for kernel. 26761da177e4SLinus Torvalds * Should be candidate for net/ipv4/utils.c 26771da177e4SLinus Torvalds * --ro 26781da177e4SLinus Torvalds */ 26791da177e4SLinus Torvalds 26801da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]) 26811da177e4SLinus Torvalds { 26821da177e4SLinus Torvalds unsigned int i; 26831da177e4SLinus Torvalds unsigned int len = 0; 26841da177e4SLinus Torvalds unsigned long u; 26851da177e4SLinus Torvalds char suffix[16]; 26861da177e4SLinus Torvalds unsigned int prefixlen = 0; 26871da177e4SLinus Torvalds unsigned int suffixlen = 0; 2688252e3346SAl Viro __be32 tmp; 26891da177e4SLinus Torvalds 2690222f1806SLuiz Capitulino for (i = 0; i < 16; i++) 2691222f1806SLuiz Capitulino ip[i] = 0; 26921da177e4SLinus Torvalds 26931da177e4SLinus Torvalds for (;;) { 26941da177e4SLinus Torvalds if (*s == ':') { 26951da177e4SLinus Torvalds len++; 26961da177e4SLinus Torvalds if (s[1] == ':') { /* Found "::", skip to part 2 */ 26971da177e4SLinus Torvalds s += 2; 26981da177e4SLinus Torvalds len++; 26991da177e4SLinus Torvalds break; 27001da177e4SLinus Torvalds } 27011da177e4SLinus Torvalds s++; 27021da177e4SLinus Torvalds } 27031da177e4SLinus Torvalds { 27041da177e4SLinus Torvalds char *tmp; 27051da177e4SLinus Torvalds u = simple_strtoul(s, &tmp, 16); 27061da177e4SLinus Torvalds i = tmp - s; 27071da177e4SLinus Torvalds } 27081da177e4SLinus Torvalds 2709222f1806SLuiz Capitulino if (!i) 2710222f1806SLuiz Capitulino return 0; 27111da177e4SLinus Torvalds if (prefixlen == 12 && s[i] == '.') { 27121da177e4SLinus Torvalds 27131da177e4SLinus Torvalds /* the last 4 bytes may be written as IPv4 address */ 27141da177e4SLinus Torvalds 27151da177e4SLinus Torvalds tmp = in_aton(s); 27161da177e4SLinus Torvalds memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); 27171da177e4SLinus Torvalds return i + len; 27181da177e4SLinus Torvalds } 27191da177e4SLinus Torvalds ip[prefixlen++] = (u >> 8); 27201da177e4SLinus Torvalds ip[prefixlen++] = (u & 255); 2721222f1806SLuiz Capitulino s += i; 2722222f1806SLuiz Capitulino len += i; 27231da177e4SLinus Torvalds if (prefixlen == 16) 27241da177e4SLinus Torvalds return len; 27251da177e4SLinus Torvalds } 27261da177e4SLinus Torvalds 27271da177e4SLinus Torvalds /* part 2, after "::" */ 27281da177e4SLinus Torvalds for (;;) { 27291da177e4SLinus Torvalds if (*s == ':') { 27301da177e4SLinus Torvalds if (suffixlen == 0) 27311da177e4SLinus Torvalds break; 27321da177e4SLinus Torvalds s++; 27331da177e4SLinus Torvalds len++; 27341da177e4SLinus Torvalds } else if (suffixlen != 0) 27351da177e4SLinus Torvalds break; 27361da177e4SLinus Torvalds { 27371da177e4SLinus Torvalds char *tmp; 27381da177e4SLinus Torvalds u = simple_strtol(s, &tmp, 16); 27391da177e4SLinus Torvalds i = tmp - s; 27401da177e4SLinus Torvalds } 27411da177e4SLinus Torvalds if (!i) { 2742222f1806SLuiz Capitulino if (*s) 2743222f1806SLuiz Capitulino len--; 27441da177e4SLinus Torvalds break; 27451da177e4SLinus Torvalds } 27461da177e4SLinus Torvalds if (suffixlen + prefixlen <= 12 && s[i] == '.') { 27471da177e4SLinus Torvalds tmp = in_aton(s); 2748222f1806SLuiz Capitulino memcpy((struct in_addr *)(suffix + suffixlen), &tmp, 2749222f1806SLuiz Capitulino sizeof(tmp)); 27501da177e4SLinus Torvalds suffixlen += 4; 27511da177e4SLinus Torvalds len += strlen(s); 27521da177e4SLinus Torvalds break; 27531da177e4SLinus Torvalds } 27541da177e4SLinus Torvalds suffix[suffixlen++] = (u >> 8); 27551da177e4SLinus Torvalds suffix[suffixlen++] = (u & 255); 2756222f1806SLuiz Capitulino s += i; 2757222f1806SLuiz Capitulino len += i; 27581da177e4SLinus Torvalds if (prefixlen + suffixlen == 16) 27591da177e4SLinus Torvalds break; 27601da177e4SLinus Torvalds } 27611da177e4SLinus Torvalds for (i = 0; i < suffixlen; i++) 27621da177e4SLinus Torvalds ip[16 - suffixlen + i] = suffix[i]; 27631da177e4SLinus Torvalds return len; 27641da177e4SLinus Torvalds } 27651da177e4SLinus Torvalds 2766222f1806SLuiz Capitulino static char tohex(char hexdigit) 2767222f1806SLuiz Capitulino { 27681da177e4SLinus Torvalds return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; 27691da177e4SLinus Torvalds } 27701da177e4SLinus Torvalds 2771222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i) 2772222f1806SLuiz Capitulino { 27731da177e4SLinus Torvalds char *bak = s; 2774222f1806SLuiz Capitulino *s = tohex((i >> 12) & 0xf); 2775222f1806SLuiz Capitulino if (s != bak || *s != '0') 2776222f1806SLuiz Capitulino ++s; 2777222f1806SLuiz Capitulino *s = tohex((i >> 8) & 0xf); 2778222f1806SLuiz Capitulino if (s != bak || *s != '0') 2779222f1806SLuiz Capitulino ++s; 2780222f1806SLuiz Capitulino *s = tohex((i >> 4) & 0xf); 2781222f1806SLuiz Capitulino if (s != bak || *s != '0') 2782222f1806SLuiz Capitulino ++s; 27831da177e4SLinus Torvalds *s = tohex(i & 0xf); 27841da177e4SLinus Torvalds return s - bak + 1; 27851da177e4SLinus Torvalds } 27861da177e4SLinus Torvalds 2787222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16]) 2788222f1806SLuiz Capitulino { 27891da177e4SLinus Torvalds unsigned int len; 27901da177e4SLinus Torvalds unsigned int i; 27911da177e4SLinus Torvalds unsigned int temp; 27921da177e4SLinus Torvalds unsigned int compressing; 27931da177e4SLinus Torvalds int j; 27941da177e4SLinus Torvalds 2795222f1806SLuiz Capitulino len = 0; 2796222f1806SLuiz Capitulino compressing = 0; 27971da177e4SLinus Torvalds for (j = 0; j < 16; j += 2) { 27981da177e4SLinus Torvalds 27991da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX 28001da177e4SLinus Torvalds if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { 28011da177e4SLinus Torvalds inet_ntoa_r(*(struct in_addr *)(ip + 12), s); 28021da177e4SLinus Torvalds temp = strlen(s); 28031da177e4SLinus Torvalds return len + temp; 28041da177e4SLinus Torvalds } 28051da177e4SLinus Torvalds #endif 28061da177e4SLinus Torvalds temp = ((unsigned long)(unsigned char)ip[j] << 8) + 28071da177e4SLinus Torvalds (unsigned long)(unsigned char)ip[j + 1]; 28081da177e4SLinus Torvalds if (temp == 0) { 28091da177e4SLinus Torvalds if (!compressing) { 28101da177e4SLinus Torvalds compressing = 1; 28111da177e4SLinus Torvalds if (j == 0) { 2812222f1806SLuiz Capitulino *s++ = ':'; 2813222f1806SLuiz Capitulino ++len; 28141da177e4SLinus Torvalds } 28151da177e4SLinus Torvalds } 28161da177e4SLinus Torvalds } else { 28171da177e4SLinus Torvalds if (compressing) { 28181da177e4SLinus Torvalds compressing = 0; 2819222f1806SLuiz Capitulino *s++ = ':'; 2820222f1806SLuiz Capitulino ++len; 28211da177e4SLinus Torvalds } 2822222f1806SLuiz Capitulino i = fmt_xlong(s, temp); 2823222f1806SLuiz Capitulino len += i; 2824222f1806SLuiz Capitulino s += i; 28251da177e4SLinus Torvalds if (j < 14) { 28261da177e4SLinus Torvalds *s++ = ':'; 28271da177e4SLinus Torvalds ++len; 28281da177e4SLinus Torvalds } 28291da177e4SLinus Torvalds } 28301da177e4SLinus Torvalds } 28311da177e4SLinus Torvalds if (compressing) { 2832222f1806SLuiz Capitulino *s++ = ':'; 2833222f1806SLuiz Capitulino ++len; 28341da177e4SLinus Torvalds } 28351da177e4SLinus Torvalds *s = 0; 28361da177e4SLinus Torvalds return len; 28371da177e4SLinus Torvalds } 28381da177e4SLinus Torvalds 28391da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 28401da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 28411da177e4SLinus Torvalds { 28421da177e4SLinus Torvalds struct sk_buff *skb = NULL; 28431da177e4SLinus Torvalds __u8 *eth; 28441da177e4SLinus Torvalds struct udphdr *udph; 28451da177e4SLinus Torvalds int datalen; 28461da177e4SLinus Torvalds struct ipv6hdr *iph; 28471da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2848d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2849ca6549afSSteven Whitehouse __be32 *mpls; 285034954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 285134954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 285234954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 285334954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2854ca6549afSSteven Whitehouse 2855ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2856d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 28571da177e4SLinus Torvalds 285834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2859d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 286034954ddcSFrancesco Fondelli 286164053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 286264053beeSRobert Olsson * fields. 286364053beeSRobert Olsson */ 286464053beeSRobert Olsson mod_cur_headers(pkt_dev); 286564053beeSRobert Olsson 2866ca6549afSSteven Whitehouse skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + 286716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead, GFP_ATOMIC); 28681da177e4SLinus Torvalds if (!skb) { 28691da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 28701da177e4SLinus Torvalds return NULL; 28711da177e4SLinus Torvalds } 28721da177e4SLinus Torvalds 28731da177e4SLinus Torvalds skb_reserve(skb, 16); 28741da177e4SLinus Torvalds 28751da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 28761da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2877ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2878ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2879ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 288034954ddcSFrancesco Fondelli 288134954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 288234954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 288334954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 28840f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 28850f37c605SAl Viro pkt_dev->svlan_cfi, 28860f37c605SAl Viro pkt_dev->svlan_p); 288734954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2888d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 288934954ddcSFrancesco Fondelli } 289034954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 28910f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 28920f37c605SAl Viro pkt_dev->vlan_cfi, 28930f37c605SAl Viro pkt_dev->vlan_p); 289434954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2895d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 289634954ddcSFrancesco Fondelli } 289734954ddcSFrancesco Fondelli 289827a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 2899b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); 2900ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); 2901ddc7b8e3SArnaldo Carvalho de Melo 2902ddc7b8e3SArnaldo Carvalho de Melo iph = ipv6_hdr(skb); 2903ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 29041da177e4SLinus Torvalds 29051da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2906252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 29071da177e4SLinus Torvalds 2908ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2909ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 2910ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 291116dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 29121da177e4SLinus Torvalds 29131da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) { 29141da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 29151da177e4SLinus Torvalds if (net_ratelimit()) 2916222f1806SLuiz Capitulino printk(KERN_INFO "pktgen: increased datalen to %d\n", 2917222f1806SLuiz Capitulino datalen); 29181da177e4SLinus Torvalds } 29191da177e4SLinus Torvalds 29201da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 29211da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 29221da177e4SLinus Torvalds udph->len = htons(datalen + sizeof(struct udphdr)); 29231da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 29241da177e4SLinus Torvalds 2925d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 29261da177e4SLinus Torvalds 29271ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 29281ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 2929252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 29301ca7768cSFrancesco Fondelli } 29311ca7768cSFrancesco Fondelli 29321da177e4SLinus Torvalds iph->hop_limit = 32; 29331da177e4SLinus Torvalds 29341da177e4SLinus Torvalds iph->payload_len = htons(sizeof(struct udphdr) + datalen); 29351da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 29361da177e4SLinus Torvalds 29371da177e4SLinus Torvalds ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); 29381da177e4SLinus Torvalds ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); 29391da177e4SLinus Torvalds 2940b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 294116dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 2942ca6549afSSteven Whitehouse skb->protocol = protocol; 29431da177e4SLinus Torvalds skb->dev = odev; 29441da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 29451da177e4SLinus Torvalds 29461da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 29471da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 29481da177e4SLinus Torvalds else { 29491da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 29501da177e4SLinus Torvalds int i; 29511da177e4SLinus Torvalds 29521da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 29531da177e4SLinus Torvalds 29541da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 29551da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 29561da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 29571da177e4SLinus Torvalds skb_put(skb, datalen - frags * PAGE_SIZE); 29581da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 29591da177e4SLinus Torvalds } 29601da177e4SLinus Torvalds 29611da177e4SLinus Torvalds i = 0; 29621da177e4SLinus Torvalds while (datalen > 0) { 29631da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 29641da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 29651da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 29661da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 29671da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 29681da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 29691da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 29701da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 29711da177e4SLinus Torvalds i++; 29721da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 29731da177e4SLinus Torvalds } 29741da177e4SLinus Torvalds 29751da177e4SLinus Torvalds while (i < frags) { 29761da177e4SLinus Torvalds int rem; 29771da177e4SLinus Torvalds 29781da177e4SLinus Torvalds if (i == 0) 29791da177e4SLinus Torvalds break; 29801da177e4SLinus Torvalds 29811da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 29821da177e4SLinus Torvalds if (rem == 0) 29831da177e4SLinus Torvalds break; 29841da177e4SLinus Torvalds 29851da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 29861da177e4SLinus Torvalds 2987222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 2988222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 29891da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2990222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 2991222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 2992222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 2993222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 29941da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 29951da177e4SLinus Torvalds i++; 29961da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 29971da177e4SLinus Torvalds } 29981da177e4SLinus Torvalds } 29991da177e4SLinus Torvalds 30001da177e4SLinus Torvalds /* Stamp the time, and sequence number, convert them to network byte order */ 30011da177e4SLinus Torvalds /* should we update cloned packets too ? */ 30021da177e4SLinus Torvalds if (pgh) { 30031da177e4SLinus Torvalds struct timeval timestamp; 30041da177e4SLinus Torvalds 30051da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 30061da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 30071da177e4SLinus Torvalds 30081da177e4SLinus Torvalds do_gettimeofday(×tamp); 30091da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 30101da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 30111da177e4SLinus Torvalds } 301234954ddcSFrancesco Fondelli /* pkt_dev->seq_num++; FF: you really mean this? */ 30131da177e4SLinus Torvalds 30141da177e4SLinus Torvalds return skb; 30151da177e4SLinus Torvalds } 30161da177e4SLinus Torvalds 30171da177e4SLinus Torvalds static inline struct sk_buff *fill_packet(struct net_device *odev, 30181da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 30191da177e4SLinus Torvalds { 30201da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 30211da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 30221da177e4SLinus Torvalds else 30231da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 30241da177e4SLinus Torvalds } 30251da177e4SLinus Torvalds 30261da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 30271da177e4SLinus Torvalds { 30281da177e4SLinus Torvalds pkt_dev->seq_num = 1; 30291da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 30301da177e4SLinus Torvalds pkt_dev->sofar = 0; 30311da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 30321da177e4SLinus Torvalds pkt_dev->errors = 0; 30331da177e4SLinus Torvalds } 30341da177e4SLinus Torvalds 30351da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 30361da177e4SLinus Torvalds 30371da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 30381da177e4SLinus Torvalds { 3039c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 30401da177e4SLinus Torvalds int started = 0; 30411da177e4SLinus Torvalds 304225c4e53aSStephen Hemminger pr_debug("pktgen: entering pktgen_run. %p\n", t); 30431da177e4SLinus Torvalds 30441da177e4SLinus Torvalds if_lock(t); 3045c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 30461da177e4SLinus Torvalds 30471da177e4SLinus Torvalds /* 30481da177e4SLinus Torvalds * setup odev and create initial packet. 30491da177e4SLinus Torvalds */ 30501da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 30511da177e4SLinus Torvalds 30521da177e4SLinus Torvalds if (pkt_dev->odev) { 30531da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 30541da177e4SLinus Torvalds pkt_dev->running = 1; /* Cranke yeself! */ 30551da177e4SLinus Torvalds pkt_dev->skb = NULL; 30561da177e4SLinus Torvalds pkt_dev->started_at = getCurUs(); 30571da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */ 30581da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 305916dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 30601da177e4SLinus Torvalds 30611da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 30621da177e4SLinus Torvalds started++; 3063222f1806SLuiz Capitulino } else 30641da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 30651da177e4SLinus Torvalds } 30661da177e4SLinus Torvalds if_unlock(t); 3067222f1806SLuiz Capitulino if (started) 3068222f1806SLuiz Capitulino t->control &= ~(T_STOP); 30691da177e4SLinus Torvalds } 30701da177e4SLinus Torvalds 30711da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void) 30721da177e4SLinus Torvalds { 3073cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 30741da177e4SLinus Torvalds 307525c4e53aSStephen Hemminger pr_debug("pktgen: entering pktgen_stop_all_threads_ifs.\n"); 30761da177e4SLinus Torvalds 30776146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3078cdcdbe0bSLuiz Capitulino 3079cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 308095ed63f7SArthur Kepner t->control |= T_STOP; 3081cdcdbe0bSLuiz Capitulino 30826146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 30831da177e4SLinus Torvalds } 30841da177e4SLinus Torvalds 30851da177e4SLinus Torvalds static int thread_is_running(struct pktgen_thread *t) 30861da177e4SLinus Torvalds { 3087c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 30881da177e4SLinus Torvalds int res = 0; 30891da177e4SLinus Torvalds 3090c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 3091c26a8016SLuiz Capitulino if (pkt_dev->running) { 30921da177e4SLinus Torvalds res = 1; 30931da177e4SLinus Torvalds break; 30941da177e4SLinus Torvalds } 30951da177e4SLinus Torvalds return res; 30961da177e4SLinus Torvalds } 30971da177e4SLinus Torvalds 30981da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 30991da177e4SLinus Torvalds { 31001da177e4SLinus Torvalds if_lock(t); 31011da177e4SLinus Torvalds 31021da177e4SLinus Torvalds while (thread_is_running(t)) { 31031da177e4SLinus Torvalds 31041da177e4SLinus Torvalds if_unlock(t); 31051da177e4SLinus Torvalds 31061da177e4SLinus Torvalds msleep_interruptible(100); 31071da177e4SLinus Torvalds 31081da177e4SLinus Torvalds if (signal_pending(current)) 31091da177e4SLinus Torvalds goto signal; 31101da177e4SLinus Torvalds if_lock(t); 31111da177e4SLinus Torvalds } 31121da177e4SLinus Torvalds if_unlock(t); 31131da177e4SLinus Torvalds return 1; 31141da177e4SLinus Torvalds signal: 31151da177e4SLinus Torvalds return 0; 31161da177e4SLinus Torvalds } 31171da177e4SLinus Torvalds 31181da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void) 31191da177e4SLinus Torvalds { 3120cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31211da177e4SLinus Torvalds int sig = 1; 31221da177e4SLinus Torvalds 31236146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3124cdcdbe0bSLuiz Capitulino 3125cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 31261da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3127222f1806SLuiz Capitulino if (sig == 0) 3128222f1806SLuiz Capitulino break; 31291da177e4SLinus Torvalds } 3130cdcdbe0bSLuiz Capitulino 3131cdcdbe0bSLuiz Capitulino if (sig == 0) 3132cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 31331da177e4SLinus Torvalds t->control |= (T_STOP); 3134cdcdbe0bSLuiz Capitulino 31356146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 31361da177e4SLinus Torvalds return sig; 31371da177e4SLinus Torvalds } 31381da177e4SLinus Torvalds 31391da177e4SLinus Torvalds static void pktgen_run_all_threads(void) 31401da177e4SLinus Torvalds { 3141cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31421da177e4SLinus Torvalds 314325c4e53aSStephen Hemminger pr_debug("pktgen: entering pktgen_run_all_threads.\n"); 31441da177e4SLinus Torvalds 31456146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 31461da177e4SLinus Torvalds 3147cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 31481da177e4SLinus Torvalds t->control |= (T_RUN); 3149cdcdbe0bSLuiz Capitulino 31506146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 31511da177e4SLinus Torvalds 3152121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 31531da177e4SLinus Torvalds 31541da177e4SLinus Torvalds pktgen_wait_all_threads_run(); 31551da177e4SLinus Torvalds } 31561da177e4SLinus Torvalds 31571da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 31581da177e4SLinus Torvalds { 31591da177e4SLinus Torvalds __u64 total_us, bps, mbps, pps, idle; 31601da177e4SLinus Torvalds char *p = pkt_dev->result; 31611da177e4SLinus Torvalds 31621da177e4SLinus Torvalds total_us = pkt_dev->stopped_at - pkt_dev->started_at; 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds idle = pkt_dev->idle_acc; 31651da177e4SLinus Torvalds 31661da177e4SLinus Torvalds p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 31671da177e4SLinus Torvalds (unsigned long long)total_us, 31681da177e4SLinus Torvalds (unsigned long long)(total_us - idle), 31691da177e4SLinus Torvalds (unsigned long long)idle, 31701da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 31711da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 31721da177e4SLinus Torvalds 31731da177e4SLinus Torvalds pps = pkt_dev->sofar * USEC_PER_SEC; 31741da177e4SLinus Torvalds 31751da177e4SLinus Torvalds while ((total_us >> 32) != 0) { 31761da177e4SLinus Torvalds pps >>= 1; 31771da177e4SLinus Torvalds total_us >>= 1; 31781da177e4SLinus Torvalds } 31791da177e4SLinus Torvalds 31801da177e4SLinus Torvalds do_div(pps, total_us); 31811da177e4SLinus Torvalds 31821da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 31831da177e4SLinus Torvalds 31841da177e4SLinus Torvalds mbps = bps; 31851da177e4SLinus Torvalds do_div(mbps, 1000000); 31861da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 31871da177e4SLinus Torvalds (unsigned long long)pps, 31881da177e4SLinus Torvalds (unsigned long long)mbps, 31891da177e4SLinus Torvalds (unsigned long long)bps, 31901da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 31911da177e4SLinus Torvalds } 31921da177e4SLinus Torvalds 31931da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 31941da177e4SLinus Torvalds 31951da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 31961da177e4SLinus Torvalds { 3197222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 31981da177e4SLinus Torvalds 31991da177e4SLinus Torvalds if (!pkt_dev->running) { 320025a8b254SDavid S. Miller printk(KERN_WARNING "pktgen: interface: %s is already " 320125a8b254SDavid S. Miller "stopped\n", pkt_dev->odev->name); 32021da177e4SLinus Torvalds return -EINVAL; 32031da177e4SLinus Torvalds } 32041da177e4SLinus Torvalds 32051da177e4SLinus Torvalds pkt_dev->stopped_at = getCurUs(); 32061da177e4SLinus Torvalds pkt_dev->running = 0; 32071da177e4SLinus Torvalds 320895ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 32091da177e4SLinus Torvalds 32101da177e4SLinus Torvalds return 0; 32111da177e4SLinus Torvalds } 32121da177e4SLinus Torvalds 32131da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 32141da177e4SLinus Torvalds { 3215c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 32161da177e4SLinus Torvalds 32171da177e4SLinus Torvalds if_lock(t); 32181da177e4SLinus Torvalds 3219c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3220c26a8016SLuiz Capitulino if (!pkt_dev->running) 3221222f1806SLuiz Capitulino continue; 3222222f1806SLuiz Capitulino if (best == NULL) 3223c26a8016SLuiz Capitulino best = pkt_dev; 3224c26a8016SLuiz Capitulino else if (pkt_dev->next_tx_us < best->next_tx_us) 3225c26a8016SLuiz Capitulino best = pkt_dev; 32261da177e4SLinus Torvalds } 32271da177e4SLinus Torvalds if_unlock(t); 32281da177e4SLinus Torvalds return best; 32291da177e4SLinus Torvalds } 32301da177e4SLinus Torvalds 3231222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3232222f1806SLuiz Capitulino { 3233c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 32341da177e4SLinus Torvalds 323525c4e53aSStephen Hemminger pr_debug("pktgen: entering pktgen_stop\n"); 32361da177e4SLinus Torvalds 32371da177e4SLinus Torvalds if_lock(t); 32381da177e4SLinus Torvalds 3239c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3240c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 3241c26a8016SLuiz Capitulino if (pkt_dev->skb) 3242c26a8016SLuiz Capitulino kfree_skb(pkt_dev->skb); 324395ed63f7SArthur Kepner 3244c26a8016SLuiz Capitulino pkt_dev->skb = NULL; 324595ed63f7SArthur Kepner } 324695ed63f7SArthur Kepner 324795ed63f7SArthur Kepner if_unlock(t); 324895ed63f7SArthur Kepner } 324995ed63f7SArthur Kepner 325095ed63f7SArthur Kepner /* 325195ed63f7SArthur Kepner * one of our devices needs to be removed - find it 325295ed63f7SArthur Kepner * and remove it 325395ed63f7SArthur Kepner */ 325495ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 325595ed63f7SArthur Kepner { 3256c26a8016SLuiz Capitulino struct list_head *q, *n; 3257c26a8016SLuiz Capitulino struct pktgen_dev *cur; 325895ed63f7SArthur Kepner 325925c4e53aSStephen Hemminger pr_debug("pktgen: entering pktgen_rem_one_if\n"); 326095ed63f7SArthur Kepner 326195ed63f7SArthur Kepner if_lock(t); 326295ed63f7SArthur Kepner 3263c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3264c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 326595ed63f7SArthur Kepner 3266222f1806SLuiz Capitulino if (!cur->removal_mark) 3267222f1806SLuiz Capitulino continue; 326895ed63f7SArthur Kepner 326995ed63f7SArthur Kepner if (cur->skb) 327095ed63f7SArthur Kepner kfree_skb(cur->skb); 327195ed63f7SArthur Kepner cur->skb = NULL; 327295ed63f7SArthur Kepner 327395ed63f7SArthur Kepner pktgen_remove_device(t, cur); 327495ed63f7SArthur Kepner 327595ed63f7SArthur Kepner break; 327695ed63f7SArthur Kepner } 32771da177e4SLinus Torvalds 32781da177e4SLinus Torvalds if_unlock(t); 32791da177e4SLinus Torvalds } 32801da177e4SLinus Torvalds 32811da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 32821da177e4SLinus Torvalds { 3283c26a8016SLuiz Capitulino struct list_head *q, *n; 3284c26a8016SLuiz Capitulino struct pktgen_dev *cur; 32851da177e4SLinus Torvalds 32861da177e4SLinus Torvalds /* Remove all devices, free mem */ 32871da177e4SLinus Torvalds 328825c4e53aSStephen Hemminger pr_debug("pktgen: entering pktgen_rem_all_ifs\n"); 32891da177e4SLinus Torvalds if_lock(t); 32901da177e4SLinus Torvalds 3291c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3292c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 329395ed63f7SArthur Kepner 329495ed63f7SArthur Kepner if (cur->skb) 329595ed63f7SArthur Kepner kfree_skb(cur->skb); 329695ed63f7SArthur Kepner cur->skb = NULL; 329795ed63f7SArthur Kepner 32981da177e4SLinus Torvalds pktgen_remove_device(t, cur); 32991da177e4SLinus Torvalds } 33001da177e4SLinus Torvalds 33011da177e4SLinus Torvalds if_unlock(t); 33021da177e4SLinus Torvalds } 33031da177e4SLinus Torvalds 33041da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 33051da177e4SLinus Torvalds { 33061da177e4SLinus Torvalds /* Remove from the thread list */ 33071da177e4SLinus Torvalds 3308ee74baa7SDavid S. Miller remove_proc_entry(t->tsk->comm, pg_proc_dir); 33091da177e4SLinus Torvalds 33106146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 33111da177e4SLinus Torvalds 3312cdcdbe0bSLuiz Capitulino list_del(&t->th_list); 3313cdcdbe0bSLuiz Capitulino 33146146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 33151da177e4SLinus Torvalds } 33161da177e4SLinus Torvalds 33171da177e4SLinus Torvalds static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) 33181da177e4SLinus Torvalds { 33191da177e4SLinus Torvalds struct net_device *odev = NULL; 33201da177e4SLinus Torvalds __u64 idle_start = 0; 33211da177e4SLinus Torvalds int ret; 33221da177e4SLinus Torvalds 33231da177e4SLinus Torvalds odev = pkt_dev->odev; 33241da177e4SLinus Torvalds 33251da177e4SLinus Torvalds if (pkt_dev->delay_us || pkt_dev->delay_ns) { 33261da177e4SLinus Torvalds u64 now; 33271da177e4SLinus Torvalds 33281da177e4SLinus Torvalds now = getCurUs(); 33291da177e4SLinus Torvalds if (now < pkt_dev->next_tx_us) 33301da177e4SLinus Torvalds spin(pkt_dev, pkt_dev->next_tx_us); 33311da177e4SLinus Torvalds 33321da177e4SLinus Torvalds /* This is max DELAY, this has special meaning of 33331da177e4SLinus Torvalds * "never transmit" 33341da177e4SLinus Torvalds */ 33351da177e4SLinus Torvalds if (pkt_dev->delay_us == 0x7FFFFFFF) { 33361da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us; 33371da177e4SLinus Torvalds pkt_dev->next_tx_ns = pkt_dev->delay_ns; 33381da177e4SLinus Torvalds goto out; 33391da177e4SLinus Torvalds } 33401da177e4SLinus Torvalds } 33411da177e4SLinus Torvalds 3342f25f4e44SPeter P Waskiewicz Jr if ((netif_queue_stopped(odev) || 3343378be2c0SRobert Olsson (pkt_dev->skb && 3344378be2c0SRobert Olsson netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) || 3345f25f4e44SPeter P Waskiewicz Jr need_resched()) { 33461da177e4SLinus Torvalds idle_start = getCurUs(); 33471da177e4SLinus Torvalds 33481da177e4SLinus Torvalds if (!netif_running(odev)) { 33491da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 335095ed63f7SArthur Kepner if (pkt_dev->skb) 335195ed63f7SArthur Kepner kfree_skb(pkt_dev->skb); 335295ed63f7SArthur Kepner pkt_dev->skb = NULL; 33531da177e4SLinus Torvalds goto out; 33541da177e4SLinus Torvalds } 33551da177e4SLinus Torvalds if (need_resched()) 33561da177e4SLinus Torvalds schedule(); 33571da177e4SLinus Torvalds 33581da177e4SLinus Torvalds pkt_dev->idle_acc += getCurUs() - idle_start; 33591da177e4SLinus Torvalds 3360f25f4e44SPeter P Waskiewicz Jr if (netif_queue_stopped(odev) || 3361f25f4e44SPeter P Waskiewicz Jr netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) { 33621da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); /* TODO */ 33631da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 33641da177e4SLinus Torvalds goto out; /* Try the next interface */ 33651da177e4SLinus Torvalds } 33661da177e4SLinus Torvalds } 33671da177e4SLinus Torvalds 33681da177e4SLinus Torvalds if (pkt_dev->last_ok || !pkt_dev->skb) { 3369222f1806SLuiz Capitulino if ((++pkt_dev->clone_count >= pkt_dev->clone_skb) 3370222f1806SLuiz Capitulino || (!pkt_dev->skb)) { 33711da177e4SLinus Torvalds /* build a new pkt */ 33721da177e4SLinus Torvalds if (pkt_dev->skb) 33731da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 33741da177e4SLinus Torvalds 33751da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 33761da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 337725a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: couldn't " 337825a8b254SDavid S. Miller "allocate skb in fill_packet.\n"); 33791da177e4SLinus Torvalds schedule(); 33801da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 33811da177e4SLinus Torvalds goto out; 33821da177e4SLinus Torvalds } 33831da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 33841da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 33851da177e4SLinus Torvalds } 33861da177e4SLinus Torvalds } 33871da177e4SLinus Torvalds 3388932ff279SHerbert Xu netif_tx_lock_bh(odev); 3389f25f4e44SPeter P Waskiewicz Jr if (!netif_queue_stopped(odev) && 3390f25f4e44SPeter P Waskiewicz Jr !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) { 33911da177e4SLinus Torvalds 33921da177e4SLinus Torvalds atomic_inc(&(pkt_dev->skb->users)); 33931da177e4SLinus Torvalds retry_now: 33941da177e4SLinus Torvalds ret = odev->hard_start_xmit(pkt_dev->skb, odev); 33951da177e4SLinus Torvalds if (likely(ret == NETDEV_TX_OK)) { 33961da177e4SLinus Torvalds pkt_dev->last_ok = 1; 33971da177e4SLinus Torvalds pkt_dev->sofar++; 33981da177e4SLinus Torvalds pkt_dev->seq_num++; 33991da177e4SLinus Torvalds pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; 34001da177e4SLinus Torvalds 34011da177e4SLinus Torvalds } else if (ret == NETDEV_TX_LOCKED 34021da177e4SLinus Torvalds && (odev->features & NETIF_F_LLTX)) { 34031da177e4SLinus Torvalds cpu_relax(); 34041da177e4SLinus Torvalds goto retry_now; 34051da177e4SLinus Torvalds } else { /* Retry it next time */ 34061da177e4SLinus Torvalds 34071da177e4SLinus Torvalds atomic_dec(&(pkt_dev->skb->users)); 34081da177e4SLinus Torvalds 34091da177e4SLinus Torvalds if (debug && net_ratelimit()) 34101da177e4SLinus Torvalds printk(KERN_INFO "pktgen: Hard xmit error\n"); 34111da177e4SLinus Torvalds 34121da177e4SLinus Torvalds pkt_dev->errors++; 34131da177e4SLinus Torvalds pkt_dev->last_ok = 0; 34141da177e4SLinus Torvalds } 34151da177e4SLinus Torvalds 34161da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); 34171da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 34181da177e4SLinus Torvalds 34191da177e4SLinus Torvalds pkt_dev->next_tx_us += pkt_dev->delay_us; 34201da177e4SLinus Torvalds pkt_dev->next_tx_ns += pkt_dev->delay_ns; 34211da177e4SLinus Torvalds 34221da177e4SLinus Torvalds if (pkt_dev->next_tx_ns > 1000) { 34231da177e4SLinus Torvalds pkt_dev->next_tx_us++; 34241da177e4SLinus Torvalds pkt_dev->next_tx_ns -= 1000; 34251da177e4SLinus Torvalds } 34261da177e4SLinus Torvalds } 34271da177e4SLinus Torvalds 34281da177e4SLinus Torvalds else { /* Retry it next time */ 34291da177e4SLinus Torvalds pkt_dev->last_ok = 0; 34301da177e4SLinus Torvalds pkt_dev->next_tx_us = getCurUs(); /* TODO */ 34311da177e4SLinus Torvalds pkt_dev->next_tx_ns = 0; 34321da177e4SLinus Torvalds } 34331da177e4SLinus Torvalds 3434932ff279SHerbert Xu netif_tx_unlock_bh(odev); 34351da177e4SLinus Torvalds 34361da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 34371da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 34381da177e4SLinus Torvalds if (atomic_read(&(pkt_dev->skb->users)) != 1) { 34391da177e4SLinus Torvalds idle_start = getCurUs(); 34401da177e4SLinus Torvalds while (atomic_read(&(pkt_dev->skb->users)) != 1) { 34411da177e4SLinus Torvalds if (signal_pending(current)) { 34421da177e4SLinus Torvalds break; 34431da177e4SLinus Torvalds } 34441da177e4SLinus Torvalds schedule(); 34451da177e4SLinus Torvalds } 34461da177e4SLinus Torvalds pkt_dev->idle_acc += getCurUs() - idle_start; 34471da177e4SLinus Torvalds } 34481da177e4SLinus Torvalds 34491da177e4SLinus Torvalds /* Done with this */ 34501da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 345195ed63f7SArthur Kepner if (pkt_dev->skb) 345295ed63f7SArthur Kepner kfree_skb(pkt_dev->skb); 345395ed63f7SArthur Kepner pkt_dev->skb = NULL; 34541da177e4SLinus Torvalds } 34551da177e4SLinus Torvalds out:; 34561da177e4SLinus Torvalds } 34571da177e4SLinus Torvalds 34581da177e4SLinus Torvalds /* 34591da177e4SLinus Torvalds * Main loop of the thread goes here 34601da177e4SLinus Torvalds */ 34611da177e4SLinus Torvalds 3462ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 34631da177e4SLinus Torvalds { 34641da177e4SLinus Torvalds DEFINE_WAIT(wait); 3465ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 34661da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 34671da177e4SLinus Torvalds int cpu = t->cpu; 34681da177e4SLinus Torvalds u32 max_before_softirq; 34691da177e4SLinus Torvalds u32 tx_since_softirq = 0; 34701da177e4SLinus Torvalds 3471ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 34721da177e4SLinus Torvalds 34731da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 34741da177e4SLinus Torvalds 347525c4e53aSStephen Hemminger pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid); 34761da177e4SLinus Torvalds 34771da177e4SLinus Torvalds max_before_softirq = t->max_before_softirq; 34781da177e4SLinus Torvalds 3479ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 34801da177e4SLinus Torvalds 348183144186SRafael J. Wysocki set_freezable(); 348283144186SRafael J. Wysocki 3483ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3484ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3485ee74baa7SDavid S. Miller 3486ee74baa7SDavid S. Miller if (!pkt_dev && 3487ee74baa7SDavid S. Miller (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV)) 3488ee74baa7SDavid S. Miller == 0) { 3489ee74baa7SDavid S. Miller prepare_to_wait(&(t->queue), &wait, 3490ee74baa7SDavid S. Miller TASK_INTERRUPTIBLE); 3491ee74baa7SDavid S. Miller schedule_timeout(HZ / 10); 3492ee74baa7SDavid S. Miller finish_wait(&(t->queue), &wait); 3493ee74baa7SDavid S. Miller } 34941da177e4SLinus Torvalds 34951da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 34961da177e4SLinus Torvalds 34971da177e4SLinus Torvalds if (pkt_dev) { 34981da177e4SLinus Torvalds 34991da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 35001da177e4SLinus Torvalds 35011da177e4SLinus Torvalds /* 35021da177e4SLinus Torvalds * We like to stay RUNNING but must also give 35031da177e4SLinus Torvalds * others fair share. 35041da177e4SLinus Torvalds */ 35051da177e4SLinus Torvalds 35061da177e4SLinus Torvalds tx_since_softirq += pkt_dev->last_ok; 35071da177e4SLinus Torvalds 35081da177e4SLinus Torvalds if (tx_since_softirq > max_before_softirq) { 35091da177e4SLinus Torvalds if (local_softirq_pending()) 35101da177e4SLinus Torvalds do_softirq(); 35111da177e4SLinus Torvalds tx_since_softirq = 0; 35121da177e4SLinus Torvalds } 35131da177e4SLinus Torvalds } 35141da177e4SLinus Torvalds 35151da177e4SLinus Torvalds if (t->control & T_STOP) { 35161da177e4SLinus Torvalds pktgen_stop(t); 35171da177e4SLinus Torvalds t->control &= ~(T_STOP); 35181da177e4SLinus Torvalds } 35191da177e4SLinus Torvalds 35201da177e4SLinus Torvalds if (t->control & T_RUN) { 35211da177e4SLinus Torvalds pktgen_run(t); 35221da177e4SLinus Torvalds t->control &= ~(T_RUN); 35231da177e4SLinus Torvalds } 35241da177e4SLinus Torvalds 352595ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 35261da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 352795ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 352895ed63f7SArthur Kepner } 352995ed63f7SArthur Kepner 353095ed63f7SArthur Kepner if (t->control & T_REMDEV) { 353195ed63f7SArthur Kepner pktgen_rem_one_if(t); 35321da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 35331da177e4SLinus Torvalds } 35341da177e4SLinus Torvalds 353509fe3ef4SAndrew Morton try_to_freeze(); 353609fe3ef4SAndrew Morton 3537ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 35381da177e4SLinus Torvalds } 35391da177e4SLinus Torvalds 354025c4e53aSStephen Hemminger pr_debug("pktgen: %s stopping all device\n", t->tsk->comm); 35411da177e4SLinus Torvalds pktgen_stop(t); 35421da177e4SLinus Torvalds 354325c4e53aSStephen Hemminger pr_debug("pktgen: %s removing all device\n", t->tsk->comm); 35441da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 35451da177e4SLinus Torvalds 354625c4e53aSStephen Hemminger pr_debug("pktgen: %s removing thread.\n", t->tsk->comm); 35471da177e4SLinus Torvalds pktgen_rem_thread(t); 3548cdcdbe0bSLuiz Capitulino 3549ee74baa7SDavid S. Miller return 0; 35501da177e4SLinus Torvalds } 35511da177e4SLinus Torvalds 3552222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 3553222f1806SLuiz Capitulino const char *ifname) 35541da177e4SLinus Torvalds { 3555c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 35561da177e4SLinus Torvalds if_lock(t); 35571da177e4SLinus Torvalds 3558c26a8016SLuiz Capitulino list_for_each_entry(p, &t->if_list, list) 355939df232fSStephen Hemminger if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) { 3560c26a8016SLuiz Capitulino pkt_dev = p; 35611da177e4SLinus Torvalds break; 35621da177e4SLinus Torvalds } 35631da177e4SLinus Torvalds 35641da177e4SLinus Torvalds if_unlock(t); 356525c4e53aSStephen Hemminger pr_debug("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev); 35661da177e4SLinus Torvalds return pkt_dev; 35671da177e4SLinus Torvalds } 35681da177e4SLinus Torvalds 35691da177e4SLinus Torvalds /* 35701da177e4SLinus Torvalds * Adds a dev at front of if_list. 35711da177e4SLinus Torvalds */ 35721da177e4SLinus Torvalds 3573222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3574222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 35751da177e4SLinus Torvalds { 35761da177e4SLinus Torvalds int rv = 0; 35771da177e4SLinus Torvalds 35781da177e4SLinus Torvalds if_lock(t); 35791da177e4SLinus Torvalds 35801da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 358125a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: already assigned " 358225a8b254SDavid S. Miller "to a thread.\n"); 35831da177e4SLinus Torvalds rv = -EBUSY; 35841da177e4SLinus Torvalds goto out; 35851da177e4SLinus Torvalds } 3586c26a8016SLuiz Capitulino 3587c26a8016SLuiz Capitulino list_add(&pkt_dev->list, &t->if_list); 35881da177e4SLinus Torvalds pkt_dev->pg_thread = t; 35891da177e4SLinus Torvalds pkt_dev->running = 0; 35901da177e4SLinus Torvalds 35911da177e4SLinus Torvalds out: 35921da177e4SLinus Torvalds if_unlock(t); 35931da177e4SLinus Torvalds return rv; 35941da177e4SLinus Torvalds } 35951da177e4SLinus Torvalds 35961da177e4SLinus Torvalds /* Called under thread lock */ 35971da177e4SLinus Torvalds 35981da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 35991da177e4SLinus Torvalds { 36001da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 360139df232fSStephen Hemminger int err; 36021da177e4SLinus Torvalds 36031da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 36041da177e4SLinus Torvalds 3605d50a6b56SStephen Hemminger pkt_dev = __pktgen_NN_threads(ifname, FIND); 3606d50a6b56SStephen Hemminger if (pkt_dev) { 360725a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: interface already used.\n"); 3608d50a6b56SStephen Hemminger return -EBUSY; 3609d50a6b56SStephen Hemminger } 36101da177e4SLinus Torvalds 36112845b63bSStephen Hemminger pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); 36121da177e4SLinus Torvalds if (!pkt_dev) 36131da177e4SLinus Torvalds return -ENOMEM; 36141da177e4SLinus Torvalds 36151da177e4SLinus Torvalds pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state)); 36161da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 36171da177e4SLinus Torvalds kfree(pkt_dev); 36181da177e4SLinus Torvalds return -ENOMEM; 36191da177e4SLinus Torvalds } 36201da177e4SLinus Torvalds memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); 36211da177e4SLinus Torvalds 362295ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 36231da177e4SLinus Torvalds pkt_dev->min_pkt_size = ETH_ZLEN; 36241da177e4SLinus Torvalds pkt_dev->max_pkt_size = ETH_ZLEN; 36251da177e4SLinus Torvalds pkt_dev->nfrags = 0; 36261da177e4SLinus Torvalds pkt_dev->clone_skb = pg_clone_skb_d; 36271da177e4SLinus Torvalds pkt_dev->delay_us = pg_delay_d / 1000; 36281da177e4SLinus Torvalds pkt_dev->delay_ns = pg_delay_d % 1000; 36291da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 36301da177e4SLinus Torvalds pkt_dev->sofar = 0; 36311da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 36321da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 36331da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 36341da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 36351da177e4SLinus Torvalds 363634954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 363734954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 363834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 363934954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 364034954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 364134954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 364234954ddcSFrancesco Fondelli 364339df232fSStephen Hemminger err = pktgen_setup_dev(pkt_dev, ifname); 364439df232fSStephen Hemminger if (err) 364539df232fSStephen Hemminger goto out1; 36461da177e4SLinus Torvalds 364739df232fSStephen Hemminger pkt_dev->entry = create_proc_entry(ifname, 0600, pg_proc_dir); 364839df232fSStephen Hemminger if (!pkt_dev->entry) { 364925a8b254SDavid S. Miller printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n", 3650d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 365139df232fSStephen Hemminger err = -EINVAL; 365239df232fSStephen Hemminger goto out2; 365339df232fSStephen Hemminger } 365439df232fSStephen Hemminger pkt_dev->entry->proc_fops = &pktgen_if_fops; 365539df232fSStephen Hemminger pkt_dev->entry->data = pkt_dev; 3656a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3657a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3658a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3659a553e4a6SJamal Hadi Salim #endif 366039df232fSStephen Hemminger 366139df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 366239df232fSStephen Hemminger out2: 366339df232fSStephen Hemminger dev_put(pkt_dev->odev); 366439df232fSStephen Hemminger out1: 3665a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3666a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3667a553e4a6SJamal Hadi Salim #endif 36681da177e4SLinus Torvalds if (pkt_dev->flows) 36691da177e4SLinus Torvalds vfree(pkt_dev->flows); 36701da177e4SLinus Torvalds kfree(pkt_dev); 367139df232fSStephen Hemminger return err; 36721da177e4SLinus Torvalds } 36731da177e4SLinus Torvalds 3674ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu) 36751da177e4SLinus Torvalds { 3676cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3677d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3678ee74baa7SDavid S. Miller struct task_struct *p; 36791da177e4SLinus Torvalds 36802845b63bSStephen Hemminger t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); 36811da177e4SLinus Torvalds if (!t) { 368225a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: out of memory, can't " 368325a8b254SDavid S. Miller "create new thread.\n"); 36841da177e4SLinus Torvalds return -ENOMEM; 36851da177e4SLinus Torvalds } 36861da177e4SLinus Torvalds 36871da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 36881da177e4SLinus Torvalds t->cpu = cpu; 36891da177e4SLinus Torvalds 3690ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3691ee74baa7SDavid S. Miller 3692ee74baa7SDavid S. Miller list_add_tail(&t->th_list, &pktgen_threads); 3693ee74baa7SDavid S. Miller 3694ee74baa7SDavid S. Miller p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu); 3695ee74baa7SDavid S. Miller if (IS_ERR(p)) { 369625a8b254SDavid S. Miller printk(KERN_ERR "pktgen: kernel_thread() failed " 369725a8b254SDavid S. Miller "for cpu %d\n", t->cpu); 3698ee74baa7SDavid S. Miller list_del(&t->th_list); 3699ee74baa7SDavid S. Miller kfree(t); 3700ee74baa7SDavid S. Miller return PTR_ERR(p); 3701ee74baa7SDavid S. Miller } 3702ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3703ee74baa7SDavid S. Miller t->tsk = p; 3704ee74baa7SDavid S. Miller 3705ee74baa7SDavid S. Miller pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir); 3706d50a6b56SStephen Hemminger if (!pe) { 370725a8b254SDavid S. Miller printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n", 3708ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3709ee74baa7SDavid S. Miller kthread_stop(p); 3710ee74baa7SDavid S. Miller list_del(&t->th_list); 37111da177e4SLinus Torvalds kfree(t); 37121da177e4SLinus Torvalds return -EINVAL; 37131da177e4SLinus Torvalds } 3714d50a6b56SStephen Hemminger 3715d50a6b56SStephen Hemminger pe->proc_fops = &pktgen_thread_fops; 3716d50a6b56SStephen Hemminger pe->data = t; 37171da177e4SLinus Torvalds 3718ee74baa7SDavid S. Miller wake_up_process(p); 37191da177e4SLinus Torvalds 37201da177e4SLinus Torvalds return 0; 37211da177e4SLinus Torvalds } 37221da177e4SLinus Torvalds 37231da177e4SLinus Torvalds /* 37241da177e4SLinus Torvalds * Removes a device from the thread if_list. 37251da177e4SLinus Torvalds */ 3726222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3727222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 37281da177e4SLinus Torvalds { 3729c26a8016SLuiz Capitulino struct list_head *q, *n; 3730c26a8016SLuiz Capitulino struct pktgen_dev *p; 37311da177e4SLinus Torvalds 3732c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3733c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3734c26a8016SLuiz Capitulino if (p == pkt_dev) 3735c26a8016SLuiz Capitulino list_del(&p->list); 37361da177e4SLinus Torvalds } 37371da177e4SLinus Torvalds } 37381da177e4SLinus Torvalds 3739222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3740222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 37411da177e4SLinus Torvalds { 37421da177e4SLinus Torvalds 374325c4e53aSStephen Hemminger pr_debug("pktgen: remove_device pkt_dev=%p\n", pkt_dev); 37441da177e4SLinus Torvalds 37451da177e4SLinus Torvalds if (pkt_dev->running) { 374625a8b254SDavid S. Miller printk(KERN_WARNING "pktgen: WARNING: trying to remove a " 374725a8b254SDavid S. Miller "running interface, stopping it now.\n"); 37481da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 37491da177e4SLinus Torvalds } 37501da177e4SLinus Torvalds 37511da177e4SLinus Torvalds /* Dis-associate from the interface */ 37521da177e4SLinus Torvalds 37531da177e4SLinus Torvalds if (pkt_dev->odev) { 37541da177e4SLinus Torvalds dev_put(pkt_dev->odev); 37551da177e4SLinus Torvalds pkt_dev->odev = NULL; 37561da177e4SLinus Torvalds } 37571da177e4SLinus Torvalds 37581da177e4SLinus Torvalds /* And update the thread if_list */ 37591da177e4SLinus Torvalds 37601da177e4SLinus Torvalds _rem_dev_from_if_list(t, pkt_dev); 37611da177e4SLinus Torvalds 376239df232fSStephen Hemminger if (pkt_dev->entry) 376339df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 37641da177e4SLinus Torvalds 3765a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3766a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3767a553e4a6SJamal Hadi Salim #endif 37681da177e4SLinus Torvalds if (pkt_dev->flows) 37691da177e4SLinus Torvalds vfree(pkt_dev->flows); 37701da177e4SLinus Torvalds kfree(pkt_dev); 37711da177e4SLinus Torvalds return 0; 37721da177e4SLinus Torvalds } 37731da177e4SLinus Torvalds 37741da177e4SLinus Torvalds static int __init pg_init(void) 37751da177e4SLinus Torvalds { 37761da177e4SLinus Torvalds int cpu; 3777d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3778d50a6b56SStephen Hemminger 377925a8b254SDavid S. Miller printk(KERN_INFO "%s", version); 37801da177e4SLinus Torvalds 3781d50a6b56SStephen Hemminger pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net); 3782d50a6b56SStephen Hemminger if (!pg_proc_dir) 3783d50a6b56SStephen Hemminger return -ENODEV; 3784d50a6b56SStephen Hemminger pg_proc_dir->owner = THIS_MODULE; 37851da177e4SLinus Torvalds 3786d50a6b56SStephen Hemminger pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir); 3787d50a6b56SStephen Hemminger if (pe == NULL) { 378825a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: cannot create %s " 378925a8b254SDavid S. Miller "procfs entry.\n", PGCTRL); 3790d50a6b56SStephen Hemminger proc_net_remove(PG_PROC_DIR); 37911da177e4SLinus Torvalds return -EINVAL; 37921da177e4SLinus Torvalds } 37931da177e4SLinus Torvalds 3794d50a6b56SStephen Hemminger pe->proc_fops = &pktgen_fops; 3795d50a6b56SStephen Hemminger pe->data = NULL; 37961da177e4SLinus Torvalds 37971da177e4SLinus Torvalds /* Register us to receive netdevice events */ 37981da177e4SLinus Torvalds register_netdevice_notifier(&pktgen_notifier_block); 37991da177e4SLinus Torvalds 3800670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 38018024bb24SLuiz Capitulino int err; 38021da177e4SLinus Torvalds 3803ee74baa7SDavid S. Miller err = pktgen_create_thread(cpu); 38048024bb24SLuiz Capitulino if (err) 380525a8b254SDavid S. Miller printk(KERN_WARNING "pktgen: WARNING: Cannot create " 380625a8b254SDavid S. Miller "thread for cpu %d (%d)\n", cpu, err); 38071da177e4SLinus Torvalds } 38088024bb24SLuiz Capitulino 38098024bb24SLuiz Capitulino if (list_empty(&pktgen_threads)) { 381025a8b254SDavid S. Miller printk(KERN_ERR "pktgen: ERROR: Initialization failed for " 381125a8b254SDavid S. Miller "all threads\n"); 38128024bb24SLuiz Capitulino unregister_netdevice_notifier(&pktgen_notifier_block); 38138024bb24SLuiz Capitulino remove_proc_entry(PGCTRL, pg_proc_dir); 38148024bb24SLuiz Capitulino proc_net_remove(PG_PROC_DIR); 38158024bb24SLuiz Capitulino return -ENODEV; 38168024bb24SLuiz Capitulino } 38178024bb24SLuiz Capitulino 38181da177e4SLinus Torvalds return 0; 38191da177e4SLinus Torvalds } 38201da177e4SLinus Torvalds 38211da177e4SLinus Torvalds static void __exit pg_cleanup(void) 38221da177e4SLinus Torvalds { 3823cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3824cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 38251da177e4SLinus Torvalds wait_queue_head_t queue; 38261da177e4SLinus Torvalds init_waitqueue_head(&queue); 38271da177e4SLinus Torvalds 38281da177e4SLinus Torvalds /* Stop all interfaces & threads */ 38291da177e4SLinus Torvalds 3830cdcdbe0bSLuiz Capitulino list_for_each_safe(q, n, &pktgen_threads) { 3831cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3832ee74baa7SDavid S. Miller kthread_stop(t->tsk); 3833ee74baa7SDavid S. Miller kfree(t); 38341da177e4SLinus Torvalds } 38351da177e4SLinus Torvalds 38361da177e4SLinus Torvalds /* Un-register us from receiving netdevice events */ 38371da177e4SLinus Torvalds unregister_netdevice_notifier(&pktgen_notifier_block); 38381da177e4SLinus Torvalds 38391da177e4SLinus Torvalds /* Clean up proc file system */ 3840d50a6b56SStephen Hemminger remove_proc_entry(PGCTRL, pg_proc_dir); 3841d50a6b56SStephen Hemminger proc_net_remove(PG_PROC_DIR); 38421da177e4SLinus Torvalds } 38431da177e4SLinus Torvalds 38441da177e4SLinus Torvalds module_init(pg_init); 38451da177e4SLinus Torvalds module_exit(pg_cleanup); 38461da177e4SLinus Torvalds 38471da177e4SLinus Torvalds MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se"); 38481da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 38491da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 38501da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 38511da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 38521da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 38531da177e4SLinus Torvalds module_param(debug, int, 0); 3854