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> 996de0e25SJan Engelhardt * 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 728788370aSJesper Dangaard Brouer * way. 738788370aSJesper Dangaard Brouer * The if_list is RCU protected, and the if_lock remains to protect updating 748788370aSJesper Dangaard Brouer * of if_list, from "add_device" as it invoked from userspace (via proc write). 751da177e4SLinus Torvalds * 761da177e4SLinus Torvalds * By design there should only be *one* "controlling" process. In practice 771da177e4SLinus Torvalds * multiple write accesses gives unpredictable result. Understood by "write" 781da177e4SLinus Torvalds * to /proc gives result code thats should be read be the "writer". 79b4099fabSStephen Hemminger * For practical use this should be no problem. 801da177e4SLinus Torvalds * 811da177e4SLinus Torvalds * Note when adding devices to a specific CPU there good idea to also assign 821da177e4SLinus Torvalds * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 831da177e4SLinus Torvalds * --ro 841da177e4SLinus Torvalds * 851da177e4SLinus Torvalds * Fix refcount off by one if first packet fails, potential null deref, 861da177e4SLinus Torvalds * memleak 030710- KJP 871da177e4SLinus Torvalds * 881da177e4SLinus Torvalds * First "ranges" functionality for ipv6 030726 --ro 891da177e4SLinus Torvalds * 901da177e4SLinus Torvalds * Included flow support. 030802 ANK. 911da177e4SLinus Torvalds * 921da177e4SLinus Torvalds * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> 931da177e4SLinus Torvalds * 941da177e4SLinus Torvalds * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 951da177e4SLinus Torvalds * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 961da177e4SLinus Torvalds * 971da177e4SLinus Torvalds * New xmit() return, do_div and misc clean up by Stephen Hemminger 981da177e4SLinus Torvalds * <shemminger@osdl.org> 040923 991da177e4SLinus Torvalds * 100b4099fabSStephen Hemminger * Randy Dunlap fixed u64 printk compiler waring 1011da177e4SLinus Torvalds * 1021da177e4SLinus Torvalds * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> 1031da177e4SLinus Torvalds * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 1041da177e4SLinus Torvalds * 1051da177e4SLinus Torvalds * Corrections from Nikolai Malykh (nmalykh@bilim.com) 1061da177e4SLinus Torvalds * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 1071da177e4SLinus Torvalds * 1081da177e4SLinus Torvalds * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 1091da177e4SLinus Torvalds * 050103 110ca6549afSSteven Whitehouse * 111ca6549afSSteven Whitehouse * MPLS support by Steven Whitehouse <steve@chygwyn.com> 112ca6549afSSteven Whitehouse * 11334954ddcSFrancesco Fondelli * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> 11434954ddcSFrancesco Fondelli * 115ce5d0b47SAdit Ranadive * Fixed src_mac command to set source mac of packet to value specified in 116ce5d0b47SAdit Ranadive * command by Adit Ranadive <adit.262@gmail.com> 117ce5d0b47SAdit Ranadive * 1181da177e4SLinus Torvalds */ 119f9467eaeSJoe Perches 120f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 121f9467eaeSJoe Perches 1221da177e4SLinus Torvalds #include <linux/sys.h> 1231da177e4SLinus Torvalds #include <linux/types.h> 1241da177e4SLinus Torvalds #include <linux/module.h> 1251da177e4SLinus Torvalds #include <linux/moduleparam.h> 1261da177e4SLinus Torvalds #include <linux/kernel.h> 127222fa076SLuiz Capitulino #include <linux/mutex.h> 1281da177e4SLinus Torvalds #include <linux/sched.h> 1291da177e4SLinus Torvalds #include <linux/slab.h> 1301da177e4SLinus Torvalds #include <linux/vmalloc.h> 1311da177e4SLinus Torvalds #include <linux/unistd.h> 1321da177e4SLinus Torvalds #include <linux/string.h> 1331da177e4SLinus Torvalds #include <linux/ptrace.h> 1341da177e4SLinus Torvalds #include <linux/errno.h> 1351da177e4SLinus Torvalds #include <linux/ioport.h> 1361da177e4SLinus Torvalds #include <linux/interrupt.h> 1374fc268d2SRandy Dunlap #include <linux/capability.h> 1382bc481cfSStephen Hemminger #include <linux/hrtimer.h> 13909fe3ef4SAndrew Morton #include <linux/freezer.h> 1401da177e4SLinus Torvalds #include <linux/delay.h> 1411da177e4SLinus Torvalds #include <linux/timer.h> 142cdcdbe0bSLuiz Capitulino #include <linux/list.h> 1431da177e4SLinus Torvalds #include <linux/init.h> 1441da177e4SLinus Torvalds #include <linux/skbuff.h> 1451da177e4SLinus Torvalds #include <linux/netdevice.h> 1461da177e4SLinus Torvalds #include <linux/inet.h> 1471da177e4SLinus Torvalds #include <linux/inetdevice.h> 1481da177e4SLinus Torvalds #include <linux/rtnetlink.h> 1491da177e4SLinus Torvalds #include <linux/if_arp.h> 15034954ddcSFrancesco Fondelli #include <linux/if_vlan.h> 1511da177e4SLinus Torvalds #include <linux/in.h> 1521da177e4SLinus Torvalds #include <linux/ip.h> 1531da177e4SLinus Torvalds #include <linux/ipv6.h> 1541da177e4SLinus Torvalds #include <linux/udp.h> 1551da177e4SLinus Torvalds #include <linux/proc_fs.h> 156d50a6b56SStephen Hemminger #include <linux/seq_file.h> 1571da177e4SLinus Torvalds #include <linux/wait.h> 158f404e9a6SKris Katterjohn #include <linux/etherdevice.h> 159ee74baa7SDavid S. Miller #include <linux/kthread.h> 160268bb0ceSLinus Torvalds #include <linux/prefetch.h> 161457c4cbcSEric W. Biederman #include <net/net_namespace.h> 1621da177e4SLinus Torvalds #include <net/checksum.h> 1631da177e4SLinus Torvalds #include <net/ipv6.h> 164c26bf4a5SThomas Graf #include <net/udp.h> 16573d94e94SStephen Rothwell #include <net/ip6_checksum.h> 1661da177e4SLinus Torvalds #include <net/addrconf.h> 167a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 168a553e4a6SJamal Hadi Salim #include <net/xfrm.h> 169a553e4a6SJamal Hadi Salim #endif 1704e58a027SCong Wang #include <net/netns/generic.h> 1711da177e4SLinus Torvalds #include <asm/byteorder.h> 1721da177e4SLinus Torvalds #include <linux/rcupdate.h> 1731977f032SJiri Slaby #include <linux/bitops.h> 17463adc6fbSStephen Hemminger #include <linux/io.h> 17563adc6fbSStephen Hemminger #include <linux/timex.h> 17663adc6fbSStephen Hemminger #include <linux/uaccess.h> 1771da177e4SLinus Torvalds #include <asm/dma.h> 1781da177e4SLinus Torvalds #include <asm/div64.h> /* do_div */ 1791da177e4SLinus Torvalds 18043d28b65SDaniel Turull #define VERSION "2.74" 1811da177e4SLinus Torvalds #define IP_NAME_SZ 32 182ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ 183d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100) 1841da177e4SLinus Torvalds 185f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__); 186f9467eaeSJoe Perches 1871da177e4SLinus Torvalds /* Device flag bits */ 1881da177e4SLinus Torvalds #define F_IPSRC_RND (1<<0) /* IP-Src Random */ 1891da177e4SLinus Torvalds #define F_IPDST_RND (1<<1) /* IP-Dst Random */ 1901da177e4SLinus Torvalds #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ 1911da177e4SLinus Torvalds #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ 1921da177e4SLinus Torvalds #define F_MACSRC_RND (1<<4) /* MAC-Src Random */ 1931da177e4SLinus Torvalds #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ 1941da177e4SLinus Torvalds #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ 1951da177e4SLinus Torvalds #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ 196ca6549afSSteven Whitehouse #define F_MPLS_RND (1<<8) /* Random MPLS labels */ 19734954ddcSFrancesco Fondelli #define F_VID_RND (1<<9) /* Random VLAN ID */ 19834954ddcSFrancesco Fondelli #define F_SVID_RND (1<<10) /* Random SVLAN ID */ 199007a531bSJamal Hadi Salim #define F_FLOW_SEQ (1<<11) /* Sequential flows */ 200a553e4a6SJamal Hadi Salim #define F_IPSEC_ON (1<<12) /* ipsec on for flows */ 20145b270f8SRobert Olsson #define F_QUEUE_MAP_RND (1<<13) /* queue map Random */ 202e6fce5b9SRobert Olsson #define F_QUEUE_MAP_CPU (1<<14) /* queue map mirrors smp_processor_id() */ 203e99b99b4SRobert Olsson #define F_NODE (1<<15) /* Node memory alloc*/ 204c26bf4a5SThomas Graf #define F_UDPCSUM (1<<16) /* Include UDP checksum */ 205afb84b62SJesper Dangaard Brouer #define F_NO_TIMESTAMP (1<<17) /* Don't timestamp packets (default TS) */ 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* Thread control flag bits */ 2086b80d6a6SStephen Hemminger #define T_STOP (1<<0) /* Stop run */ 2096b80d6a6SStephen Hemminger #define T_RUN (1<<1) /* Start run */ 2106b80d6a6SStephen Hemminger #define T_REMDEVALL (1<<2) /* Remove all devs */ 2116b80d6a6SStephen Hemminger #define T_REMDEV (1<<3) /* Remove one dev */ 2121da177e4SLinus Torvalds 2138788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */ 2141da177e4SLinus Torvalds #define if_lock(t) spin_lock(&(t->if_lock)); 2151da177e4SLinus Torvalds #define if_unlock(t) spin_unlock(&(t->if_lock)); 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 2181da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 219d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen" 220d50a6b56SStephen Hemminger #define PGCTRL "pgctrl" 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds #define MAX_CFLOWS 65536 2231da177e4SLinus Torvalds 22434954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 22534954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 22634954ddcSFrancesco Fondelli 227222f1806SLuiz Capitulino struct flow_state { 228252e3346SAl Viro __be32 cur_daddr; 2291da177e4SLinus Torvalds int count; 230a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 231a553e4a6SJamal Hadi Salim struct xfrm_state *x; 232a553e4a6SJamal Hadi Salim #endif 233007a531bSJamal Hadi Salim __u32 flags; 2341da177e4SLinus Torvalds }; 2351da177e4SLinus Torvalds 236007a531bSJamal Hadi Salim /* flow flag bits */ 237007a531bSJamal Hadi Salim #define F_INIT (1<<0) /* flow has been initialized */ 238007a531bSJamal Hadi Salim 2391da177e4SLinus Torvalds struct pktgen_dev { 2401da177e4SLinus Torvalds /* 2411da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 2421da177e4SLinus Torvalds */ 24339df232fSStephen Hemminger struct proc_dir_entry *entry; /* proc file */ 2441da177e4SLinus Torvalds struct pktgen_thread *pg_thread;/* the owner */ 24563adc6fbSStephen Hemminger struct list_head list; /* chaining in the thread's run-queue */ 2468788370aSJesper Dangaard Brouer struct rcu_head rcu; /* freed by RCU */ 2471da177e4SLinus Torvalds 24863adc6fbSStephen Hemminger int running; /* if false, the test will stop */ 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 2511da177e4SLinus Torvalds * we will do a random selection from within the range. 2521da177e4SLinus Torvalds */ 2531da177e4SLinus Torvalds __u32 flags; 25495ed63f7SArthur Kepner int removal_mark; /* non-zero => the device is marked for 25595ed63f7SArthur Kepner * removal by worker thread */ 2561da177e4SLinus Torvalds 25768bf9f0bSAmerigo Wang int min_pkt_size; 25868bf9f0bSAmerigo Wang int max_pkt_size; 25916dab72fSJamal Hadi Salim int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2601da177e4SLinus Torvalds int nfrags; 26126ad7879SEric Dumazet struct page *page; 262fd29cf72SStephen Hemminger u64 delay; /* nano-seconds */ 263fd29cf72SStephen Hemminger 2641da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 2651da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 2661da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 267f466dba1SJohn Fastabend __u64 errors; /* Errors when trying to transmit, */ 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds __u64 allocated_skbs; 2721da177e4SLinus Torvalds __u32 clone_count; 2731da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 27463adc6fbSStephen Hemminger * Or a failed transmit of some sort? 27563adc6fbSStephen Hemminger * This will keep sequence numbers in order 2761da177e4SLinus Torvalds */ 277fd29cf72SStephen Hemminger ktime_t next_tx; 278fd29cf72SStephen Hemminger ktime_t started_at; 279fd29cf72SStephen Hemminger ktime_t stopped_at; 280fd29cf72SStephen Hemminger u64 idle_acc; /* nano-seconds */ 281fd29cf72SStephen Hemminger 2821da177e4SLinus Torvalds __u32 seq_num; 2831da177e4SLinus Torvalds 28463adc6fbSStephen Hemminger int clone_skb; /* 28563adc6fbSStephen Hemminger * Use multiple SKBs during packet gen. 28663adc6fbSStephen Hemminger * If this number is greater than 1, then 28763adc6fbSStephen Hemminger * that many copies of the same packet will be 28863adc6fbSStephen Hemminger * sent before a new packet is allocated. 28963adc6fbSStephen Hemminger * If you want to send 1024 identical packets 29063adc6fbSStephen Hemminger * before creating a new packet, 29163adc6fbSStephen Hemminger * set clone_skb to 1024. 2921da177e4SLinus Torvalds */ 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2951da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2961da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2971da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds struct in6_addr in6_saddr; 3001da177e4SLinus Torvalds struct in6_addr in6_daddr; 3011da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 3021da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 3031da177e4SLinus Torvalds /* For ranges */ 3041da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 3051da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 3061da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 3071da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 3101da177e4SLinus Torvalds * defines the min/max for those ranges. 3111da177e4SLinus Torvalds */ 312252e3346SAl Viro __be32 saddr_min; /* inclusive, source IP address */ 313252e3346SAl Viro __be32 saddr_max; /* exclusive, source IP address */ 314252e3346SAl Viro __be32 daddr_min; /* inclusive, dest IP address */ 315252e3346SAl Viro __be32 daddr_max; /* exclusive, dest IP address */ 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 3181da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 3191da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 3201da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 3211da177e4SLinus Torvalds 3221ca7768cSFrancesco Fondelli /* DSCP + ECN */ 32363adc6fbSStephen Hemminger __u8 tos; /* six MSB of (former) IPv4 TOS 32463adc6fbSStephen Hemminger are for dscp codepoint */ 32563adc6fbSStephen Hemminger __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 32663adc6fbSStephen Hemminger (see RFC 3260, sec. 4) */ 3271ca7768cSFrancesco Fondelli 328ca6549afSSteven Whitehouse /* MPLS */ 32995c96174SEric Dumazet unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */ 330ca6549afSSteven Whitehouse __be32 labels[MAX_MPLS_LABELS]; 331ca6549afSSteven Whitehouse 33234954ddcSFrancesco Fondelli /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 33334954ddcSFrancesco Fondelli __u8 vlan_p; 33434954ddcSFrancesco Fondelli __u8 vlan_cfi; 33534954ddcSFrancesco Fondelli __u16 vlan_id; /* 0xffff means no vlan tag */ 33634954ddcSFrancesco Fondelli 33734954ddcSFrancesco Fondelli __u8 svlan_p; 33834954ddcSFrancesco Fondelli __u8 svlan_cfi; 33934954ddcSFrancesco Fondelli __u16 svlan_id; /* 0xffff means no svlan tag */ 34034954ddcSFrancesco Fondelli 3411da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 3421da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 3431da177e4SLinus Torvalds 344f404e9a6SKris Katterjohn unsigned char dst_mac[ETH_ALEN]; 345f404e9a6SKris Katterjohn unsigned char src_mac[ETH_ALEN]; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 3481da177e4SLinus Torvalds __u32 cur_src_mac_offset; 349252e3346SAl Viro __be32 cur_saddr; 350252e3346SAl Viro __be32 cur_daddr; 35166ed1e5eSEric Dumazet __u16 ip_id; 3521da177e4SLinus Torvalds __u16 cur_udp_dst; 3531da177e4SLinus Torvalds __u16 cur_udp_src; 35445b270f8SRobert Olsson __u16 cur_queue_map; 3551da177e4SLinus Torvalds __u32 cur_pkt_size; 356baac8564SEric Dumazet __u32 last_pkt_size; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds __u8 hh[14]; 3591da177e4SLinus Torvalds /* = { 3601da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds We fill in SRC address later 3631da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3641da177e4SLinus Torvalds 0x08, 0x00 3651da177e4SLinus Torvalds }; 3661da177e4SLinus Torvalds */ 3671da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 3681da177e4SLinus Torvalds 36963adc6fbSStephen Hemminger struct sk_buff *skb; /* skb we are to transmit next, used for when we 3701da177e4SLinus Torvalds * are transmitting the same one multiple times 3711da177e4SLinus Torvalds */ 37263adc6fbSStephen Hemminger struct net_device *odev; /* The out-going device. 37363adc6fbSStephen Hemminger * Note that the device should have it's 37463adc6fbSStephen Hemminger * pg_info pointer pointing back to this 37563adc6fbSStephen Hemminger * device. 37663adc6fbSStephen Hemminger * Set when the user specifies the out-going 37763adc6fbSStephen Hemminger * device name (not when the inject is 3781da177e4SLinus Torvalds * started as it used to do.) 3791da177e4SLinus Torvalds */ 380593f63b0SEric Dumazet char odevname[32]; 3811da177e4SLinus Torvalds struct flow_state *flows; 38295c96174SEric Dumazet unsigned int cflows; /* Concurrent flows (config) */ 38395c96174SEric Dumazet unsigned int lflow; /* Flow length (config) */ 38495c96174SEric Dumazet unsigned int nflows; /* accumulated flows (stats) */ 38595c96174SEric Dumazet unsigned int curfl; /* current sequenced flow (state)*/ 38645b270f8SRobert Olsson 38745b270f8SRobert Olsson u16 queue_map_min; 38845b270f8SRobert Olsson u16 queue_map_max; 3899e50e3acSJohn Fastabend __u32 skb_priority; /* skb priority field */ 390e99b99b4SRobert Olsson int node; /* Memory node */ 39145b270f8SRobert Olsson 392a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 393a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 394a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 395de4aee7dSFan Du __u32 spi; 396cf93d47eSFan Du struct dst_entry dst; 397cf93d47eSFan Du struct dst_ops dstops; 398a553e4a6SJamal Hadi Salim #endif 39939df232fSStephen Hemminger char result[512]; 4001da177e4SLinus Torvalds }; 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds struct pktgen_hdr { 403252e3346SAl Viro __be32 pgh_magic; 404252e3346SAl Viro __be32 seq_num; 405252e3346SAl Viro __be32 tv_sec; 406252e3346SAl Viro __be32 tv_usec; 4071da177e4SLinus Torvalds }; 4081da177e4SLinus Torvalds 4094e58a027SCong Wang 4104e58a027SCong Wang static int pg_net_id __read_mostly; 4114e58a027SCong Wang 4124e58a027SCong Wang struct pktgen_net { 4134e58a027SCong Wang struct net *net; 4144e58a027SCong Wang struct proc_dir_entry *proc_dir; 4154e58a027SCong Wang struct list_head pktgen_threads; 4164e58a027SCong Wang bool pktgen_exiting; 4174e58a027SCong Wang }; 418551eaff1SEric Dumazet 4191da177e4SLinus Torvalds struct pktgen_thread { 42063adc6fbSStephen Hemminger spinlock_t if_lock; /* for list of devices */ 421c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 422cdcdbe0bSLuiz Capitulino struct list_head th_list; 423ee74baa7SDavid S. Miller struct task_struct *tsk; 4241da177e4SLinus Torvalds char result[512]; 4251da177e4SLinus Torvalds 42663adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 42763adc6fbSStephen Hemminger stop ifs etc. */ 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds u32 control; 4301da177e4SLinus Torvalds int cpu; 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds wait_queue_head_t queue; 433d3ede327SDenis V. Lunev struct completion start_done; 4344e58a027SCong Wang struct pktgen_net *net; 4351da177e4SLinus Torvalds }; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds #define REMOVE 1 4381da177e4SLinus Torvalds #define FIND 0 4391da177e4SLinus Torvalds 440c3d2f52dSStephen Hemminger static const char version[] = 441f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 442f9467eaeSJoe Perches "Version: " VERSION "\n"; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4451da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 446222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4473e984840SEric Dumazet const char *ifname, bool exact); 4481da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4494e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn); 4504e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn); 4514e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn); 4523bda06a3SStephen Hemminger 4531da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4541da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 45539df232fSStephen Hemminger 4561da177e4SLinus Torvalds /* Module parameters, defaults. */ 45765c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 45865c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 45965c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 46065c5b786SStephen Hemminger static int debug __read_mostly; 4611da177e4SLinus Torvalds 462222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 4651da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 4661da177e4SLinus Torvalds }; 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds /* 4691da177e4SLinus Torvalds * /proc handling functions 4701da177e4SLinus Torvalds * 4711da177e4SLinus Torvalds */ 4721da177e4SLinus Torvalds 473d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 474d50a6b56SStephen Hemminger { 475c3d2f52dSStephen Hemminger seq_puts(seq, version); 476d50a6b56SStephen Hemminger return 0; 477d50a6b56SStephen Hemminger } 4781da177e4SLinus Torvalds 479d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 4801da177e4SLinus Torvalds size_t count, loff_t *ppos) 4811da177e4SLinus Torvalds { 482d50a6b56SStephen Hemminger char data[128]; 4834e58a027SCong Wang struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id); 4841da177e4SLinus Torvalds 48509455747SMathias Krause if (!capable(CAP_NET_ADMIN)) 48609455747SMathias Krause return -EPERM; 4871da177e4SLinus Torvalds 48820b0c718SMathias Krause if (count == 0) 48920b0c718SMathias Krause return -EINVAL; 49020b0c718SMathias Krause 491d50a6b56SStephen Hemminger if (count > sizeof(data)) 492d50a6b56SStephen Hemminger count = sizeof(data); 4931da177e4SLinus Torvalds 49409455747SMathias Krause if (copy_from_user(data, buf, count)) 49509455747SMathias Krause return -EFAULT; 49609455747SMathias Krause 49720b0c718SMathias Krause data[count - 1] = 0; /* Strip trailing '\n' and terminate string */ 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds if (!strcmp(data, "stop")) 5004e58a027SCong Wang pktgen_stop_all_threads_ifs(pn); 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds else if (!strcmp(data, "start")) 5034e58a027SCong Wang pktgen_run_all_threads(pn); 5041da177e4SLinus Torvalds 505eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 5064e58a027SCong Wang pktgen_reset_all_threads(pn); 507eb37b41cSJesse Brandeburg 5081da177e4SLinus Torvalds else 509*294a0b7fSJoe Perches pr_warn("Unknown command: %s\n", data); 5101da177e4SLinus Torvalds 51109455747SMathias Krause return count; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 514d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5151da177e4SLinus Torvalds { 516d9dda78bSAl Viro return single_open(file, pgctrl_show, PDE_DATA(inode)); 517d50a6b56SStephen Hemminger } 518d50a6b56SStephen Hemminger 5199a32144eSArjan van de Ven static const struct file_operations pktgen_fops = { 520d50a6b56SStephen Hemminger .owner = THIS_MODULE, 521d50a6b56SStephen Hemminger .open = pgctrl_open, 522d50a6b56SStephen Hemminger .read = seq_read, 523d50a6b56SStephen Hemminger .llseek = seq_lseek, 524d50a6b56SStephen Hemminger .write = pgctrl_write, 525d50a6b56SStephen Hemminger .release = single_release, 526d50a6b56SStephen Hemminger }; 527d50a6b56SStephen Hemminger 528d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 529d50a6b56SStephen Hemminger { 530648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 531fd29cf72SStephen Hemminger ktime_t stopped; 532fd29cf72SStephen Hemminger u64 idle; 5331da177e4SLinus Torvalds 534222f1806SLuiz Capitulino seq_printf(seq, 535222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 536222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 537222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5381da177e4SLinus Torvalds 539222f1806SLuiz Capitulino seq_printf(seq, 540fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 541fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 542593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5431da177e4SLinus Torvalds 544222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 545222f1806SLuiz Capitulino pkt_dev->lflow); 5461da177e4SLinus Torvalds 54745b270f8SRobert Olsson seq_printf(seq, 54845b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 54945b270f8SRobert Olsson pkt_dev->queue_map_min, 55045b270f8SRobert Olsson pkt_dev->queue_map_max); 55145b270f8SRobert Olsson 5529e50e3acSJohn Fastabend if (pkt_dev->skb_priority) 5539e50e3acSJohn Fastabend seq_printf(seq, " skb_priority: %u\n", 5549e50e3acSJohn Fastabend pkt_dev->skb_priority); 5559e50e3acSJohn Fastabend 5561da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 557222f1806SLuiz Capitulino seq_printf(seq, 55847a0200dSAlexey Dobriyan " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" 55947a0200dSAlexey Dobriyan " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", 56047a0200dSAlexey Dobriyan &pkt_dev->in6_saddr, 56147a0200dSAlexey Dobriyan &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, 56247a0200dSAlexey Dobriyan &pkt_dev->in6_daddr, 56347a0200dSAlexey Dobriyan &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); 56463adc6fbSStephen Hemminger } else { 565222f1806SLuiz Capitulino seq_printf(seq, 56663adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 56763adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 56863adc6fbSStephen Hemminger seq_printf(seq, 56963adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 57063adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 57163adc6fbSStephen Hemminger } 5721da177e4SLinus Torvalds 573d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 5741da177e4SLinus Torvalds 575e174961cSJohannes Berg seq_printf(seq, "%pM ", 576e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 577e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5781da177e4SLinus Torvalds 57997dc48e2SThomas Graf seq_puts(seq, "dst_mac: "); 580e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 5811da177e4SLinus Torvalds 582222f1806SLuiz Capitulino seq_printf(seq, 58363adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 58463adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 585222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 586222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 5871da177e4SLinus Torvalds 588222f1806SLuiz Capitulino seq_printf(seq, 589ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 5901da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 5911da177e4SLinus Torvalds 592ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 59395c96174SEric Dumazet unsigned int i; 59497dc48e2SThomas Graf seq_puts(seq, " mpls: "); 595ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 596ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 597ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 598ca6549afSSteven Whitehouse } 599ca6549afSSteven Whitehouse 60063adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 60134954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 60263adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 60363adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 60434954ddcSFrancesco Fondelli 60563adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 60634954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 60763adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 60863adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 60934954ddcSFrancesco Fondelli 61063adc6fbSStephen Hemminger if (pkt_dev->tos) 6111ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6121ca7768cSFrancesco Fondelli 61363adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6141ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6151ca7768cSFrancesco Fondelli 616e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 617e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 618e99b99b4SRobert Olsson 61997dc48e2SThomas Graf seq_puts(seq, " Flags: "); 620ca6549afSSteven Whitehouse 6211da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 62297dc48e2SThomas Graf seq_puts(seq, "IPV6 "); 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 62597dc48e2SThomas Graf seq_puts(seq, "IPSRC_RND "); 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 62897dc48e2SThomas Graf seq_puts(seq, "IPDST_RND "); 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 63197dc48e2SThomas Graf seq_puts(seq, "TXSIZE_RND "); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 63497dc48e2SThomas Graf seq_puts(seq, "UDPSRC_RND "); 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 63797dc48e2SThomas Graf seq_puts(seq, "UDPDST_RND "); 6381da177e4SLinus Torvalds 639c26bf4a5SThomas Graf if (pkt_dev->flags & F_UDPCSUM) 64097dc48e2SThomas Graf seq_puts(seq, "UDPCSUM "); 641c26bf4a5SThomas Graf 642afb84b62SJesper Dangaard Brouer if (pkt_dev->flags & F_NO_TIMESTAMP) 643afb84b62SJesper Dangaard Brouer seq_puts(seq, "NO_TIMESTAMP "); 644afb84b62SJesper Dangaard Brouer 645ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) 64697dc48e2SThomas Graf seq_puts(seq, "MPLS_RND "); 647ca6549afSSteven Whitehouse 64845b270f8SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_RND) 64997dc48e2SThomas Graf seq_puts(seq, "QUEUE_MAP_RND "); 65045b270f8SRobert Olsson 651e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 65297dc48e2SThomas Graf seq_puts(seq, "QUEUE_MAP_CPU "); 653e6fce5b9SRobert Olsson 654007a531bSJamal Hadi Salim if (pkt_dev->cflows) { 655007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) 65697dc48e2SThomas Graf seq_puts(seq, "FLOW_SEQ "); /*in sequence flows*/ 657007a531bSJamal Hadi Salim else 65897dc48e2SThomas Graf seq_puts(seq, "FLOW_RND "); 659007a531bSJamal Hadi Salim } 660007a531bSJamal Hadi Salim 661a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 6628101328bSFan Du if (pkt_dev->flags & F_IPSEC_ON) { 66397dc48e2SThomas Graf seq_puts(seq, "IPSEC "); 6648101328bSFan Du if (pkt_dev->spi) 6658101328bSFan Du seq_printf(seq, "spi:%u", pkt_dev->spi); 6668101328bSFan Du } 667a553e4a6SJamal Hadi Salim #endif 668a553e4a6SJamal Hadi Salim 6691da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 67097dc48e2SThomas Graf seq_puts(seq, "MACSRC_RND "); 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 67397dc48e2SThomas Graf seq_puts(seq, "MACDST_RND "); 6741da177e4SLinus Torvalds 67534954ddcSFrancesco Fondelli if (pkt_dev->flags & F_VID_RND) 67697dc48e2SThomas Graf seq_puts(seq, "VID_RND "); 67734954ddcSFrancesco Fondelli 67834954ddcSFrancesco Fondelli if (pkt_dev->flags & F_SVID_RND) 67997dc48e2SThomas Graf seq_puts(seq, "SVID_RND "); 68034954ddcSFrancesco Fondelli 681e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) 68297dc48e2SThomas Graf seq_puts(seq, "NODE_ALLOC "); 683e99b99b4SRobert Olsson 684d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 6851da177e4SLinus Torvalds 686fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 687398f382cSDaniel Borkmann stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at; 688fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 689fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 6901da177e4SLinus Torvalds 691222f1806SLuiz Capitulino seq_printf(seq, 692fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 6931da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 694fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 695fd29cf72SStephen Hemminger 696fd29cf72SStephen Hemminger seq_printf(seq, 697fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 698fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 699fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 700fd29cf72SStephen Hemminger (unsigned long long) idle); 7011da177e4SLinus Torvalds 702222f1806SLuiz Capitulino seq_printf(seq, 703222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 704d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 705d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 70847a0200dSAlexey Dobriyan seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", 70947a0200dSAlexey Dobriyan &pkt_dev->cur_in6_saddr, 71047a0200dSAlexey Dobriyan &pkt_dev->cur_in6_daddr); 711222f1806SLuiz Capitulino } else 7120373a946SAmerigo Wang seq_printf(seq, " cur_saddr: %pI4 cur_daddr: %pI4\n", 7130373a946SAmerigo Wang &pkt_dev->cur_saddr, &pkt_dev->cur_daddr); 7141da177e4SLinus Torvalds 715d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7161da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7171da177e4SLinus Torvalds 71845b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 71945b270f8SRobert Olsson 720d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds if (pkt_dev->result[0]) 723d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7241da177e4SLinus Torvalds else 72597dc48e2SThomas Graf seq_puts(seq, "Result: Idle\n"); 7261da177e4SLinus Torvalds 727d50a6b56SStephen Hemminger return 0; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds 730ca6549afSSteven Whitehouse 73163adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 73263adc6fbSStephen Hemminger __u32 *num) 733ca6549afSSteven Whitehouse { 734ca6549afSSteven Whitehouse int i = 0; 735ca6549afSSteven Whitehouse *num = 0; 736ca6549afSSteven Whitehouse 7371ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 73882fd5b5dSAndy Shevchenko int value; 739ca6549afSSteven Whitehouse char c; 740ca6549afSSteven Whitehouse *num <<= 4; 741ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 742ca6549afSSteven Whitehouse return -EFAULT; 74382fd5b5dSAndy Shevchenko value = hex_to_bin(c); 74482fd5b5dSAndy Shevchenko if (value >= 0) 74582fd5b5dSAndy Shevchenko *num |= value; 746ca6549afSSteven Whitehouse else 747ca6549afSSteven Whitehouse break; 748ca6549afSSteven Whitehouse } 749ca6549afSSteven Whitehouse return i; 750ca6549afSSteven Whitehouse } 751ca6549afSSteven Whitehouse 752222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 753222f1806SLuiz Capitulino unsigned int maxlen) 7541da177e4SLinus Torvalds { 7551da177e4SLinus Torvalds int i; 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7581da177e4SLinus Torvalds char c; 7591da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7601da177e4SLinus Torvalds return -EFAULT; 7611da177e4SLinus Torvalds switch (c) { 7621da177e4SLinus Torvalds case '\"': 7631da177e4SLinus Torvalds case '\n': 7641da177e4SLinus Torvalds case '\r': 7651da177e4SLinus Torvalds case '\t': 7661da177e4SLinus Torvalds case ' ': 7671da177e4SLinus Torvalds case '=': 7681da177e4SLinus Torvalds break; 7691da177e4SLinus Torvalds default: 7701da177e4SLinus Torvalds goto done; 7713ff50b79SStephen Hemminger } 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds done: 7741da177e4SLinus Torvalds return i; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 777bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen, 778bf0813bdSPaul Gortmaker unsigned long *num) 7791da177e4SLinus Torvalds { 780d6182223SPaul Gortmaker int i; 7811da177e4SLinus Torvalds *num = 0; 7821da177e4SLinus Torvalds 783d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 7841da177e4SLinus Torvalds char c; 7851da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7861da177e4SLinus Torvalds return -EFAULT; 7871da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 7881da177e4SLinus Torvalds *num *= 10; 7891da177e4SLinus Torvalds *num += c - '0'; 7901da177e4SLinus Torvalds } else 7911da177e4SLinus Torvalds break; 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds return i; 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 7971da177e4SLinus Torvalds { 798d6182223SPaul Gortmaker int i; 7991da177e4SLinus Torvalds 800d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 8011da177e4SLinus Torvalds char c; 8021da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8031da177e4SLinus Torvalds return -EFAULT; 8041da177e4SLinus Torvalds switch (c) { 8051da177e4SLinus Torvalds case '\"': 8061da177e4SLinus Torvalds case '\n': 8071da177e4SLinus Torvalds case '\r': 8081da177e4SLinus Torvalds case '\t': 8091da177e4SLinus Torvalds case ' ': 8101da177e4SLinus Torvalds goto done_str; 8111da177e4SLinus Torvalds default: 8121da177e4SLinus Torvalds break; 8133ff50b79SStephen Hemminger } 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds done_str: 8161da177e4SLinus Torvalds return i; 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds 819ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 820ca6549afSSteven Whitehouse { 82195c96174SEric Dumazet unsigned int n = 0; 822ca6549afSSteven Whitehouse char c; 823ca6549afSSteven Whitehouse ssize_t i = 0; 824ca6549afSSteven Whitehouse int len; 825ca6549afSSteven Whitehouse 826ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 827ca6549afSSteven Whitehouse do { 828ca6549afSSteven Whitehouse __u32 tmp; 8291ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 830ca6549afSSteven Whitehouse if (len <= 0) 831ca6549afSSteven Whitehouse return len; 832ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 833ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 834ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 835ca6549afSSteven Whitehouse i += len; 836ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 837ca6549afSSteven Whitehouse return -EFAULT; 838ca6549afSSteven Whitehouse i++; 839ca6549afSSteven Whitehouse n++; 840ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 841ca6549afSSteven Whitehouse return -E2BIG; 842ca6549afSSteven Whitehouse } while (c == ','); 843ca6549afSSteven Whitehouse 844ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 845ca6549afSSteven Whitehouse return i; 846ca6549afSSteven Whitehouse } 847ca6549afSSteven Whitehouse 848222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 849222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 850222f1806SLuiz Capitulino loff_t * offset) 8511da177e4SLinus Torvalds { 8528a994a71SJoe Perches struct seq_file *seq = file->private_data; 853d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 854d6182223SPaul Gortmaker int i, max, len; 8551da177e4SLinus Torvalds char name[16], valstr[32]; 8561da177e4SLinus Torvalds unsigned long value = 0; 8571da177e4SLinus Torvalds char *pg_result = NULL; 8581da177e4SLinus Torvalds int tmp = 0; 8591da177e4SLinus Torvalds char buf[128]; 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds if (count < 1) { 864*294a0b7fSJoe Perches pr_warn("wrong command format\n"); 8651da177e4SLinus Torvalds return -EINVAL; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 868d6182223SPaul Gortmaker max = count; 869d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 8701da177e4SLinus Torvalds if (tmp < 0) { 871*294a0b7fSJoe Perches pr_warn("illegal format\n"); 8721da177e4SLinus Torvalds return tmp; 8731da177e4SLinus Torvalds } 874d6182223SPaul Gortmaker i = tmp; 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds /* Read variable name */ 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 87963adc6fbSStephen Hemminger if (len < 0) 880222f1806SLuiz Capitulino return len; 88163adc6fbSStephen Hemminger 8821da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 8831da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 8841da177e4SLinus Torvalds return -EFAULT; 8851da177e4SLinus Torvalds i += len; 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds max = count - i; 8881da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 8891da177e4SLinus Torvalds if (len < 0) 8901da177e4SLinus Torvalds return len; 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds i += len; 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds if (debug) { 89586c2c0a8SDmitry Torokhov size_t copy = min_t(size_t, count, 1023); 896448d7b5dSNelson Elhage char tb[copy + 1]; 897448d7b5dSNelson Elhage if (copy_from_user(tb, user_buffer, copy)) 8981da177e4SLinus Torvalds return -EFAULT; 899448d7b5dSNelson Elhage tb[copy] = 0; 900f342cda7SJoe Perches pr_debug("%s,%lu buffer -:%s:-\n", 901f342cda7SJoe Perches name, (unsigned long)count, tb); 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9051da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 90663adc6fbSStephen Hemminger if (len < 0) 907222f1806SLuiz Capitulino return len; 90863adc6fbSStephen Hemminger 9091da177e4SLinus Torvalds i += len; 9101da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9111da177e4SLinus Torvalds value = 14 + 20 + 8; 9121da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9131da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9141da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9151da177e4SLinus Torvalds } 916222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 917222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9181da177e4SLinus Torvalds return count; 9191da177e4SLinus Torvalds } 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9221da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 92363adc6fbSStephen Hemminger if (len < 0) 924222f1806SLuiz Capitulino return len; 92563adc6fbSStephen Hemminger 9261da177e4SLinus Torvalds i += len; 9271da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9281da177e4SLinus Torvalds value = 14 + 20 + 8; 9291da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9301da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9311da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9321da177e4SLinus Torvalds } 933222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 934222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9351da177e4SLinus Torvalds return count; 9361da177e4SLinus Torvalds } 9371da177e4SLinus Torvalds 9381da177e4SLinus Torvalds /* Shortcut for min = max */ 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9411da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 94263adc6fbSStephen Hemminger if (len < 0) 943222f1806SLuiz Capitulino return len; 94463adc6fbSStephen Hemminger 9451da177e4SLinus Torvalds i += len; 9461da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9471da177e4SLinus Torvalds value = 14 + 20 + 8; 9481da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9491da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9501da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9511da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 9541da177e4SLinus Torvalds return count; 9551da177e4SLinus Torvalds } 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9581da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 95963adc6fbSStephen Hemminger if (len < 0) 960222f1806SLuiz Capitulino return len; 96163adc6fbSStephen Hemminger 9621da177e4SLinus Torvalds i += len; 9631da177e4SLinus Torvalds debug = value; 9641da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9651da177e4SLinus Torvalds return count; 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9691da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 97063adc6fbSStephen Hemminger if (len < 0) 971222f1806SLuiz Capitulino return len; 97263adc6fbSStephen Hemminger 9731da177e4SLinus Torvalds i += len; 9741da177e4SLinus Torvalds pkt_dev->nfrags = value; 9751da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 9761da177e4SLinus Torvalds return count; 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 9791da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 98063adc6fbSStephen Hemminger if (len < 0) 981222f1806SLuiz Capitulino return len; 98263adc6fbSStephen Hemminger 9831da177e4SLinus Torvalds i += len; 984fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 985fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 986fd29cf72SStephen Hemminger else 9879240d715SEric Dumazet pkt_dev->delay = (u64)value; 988fd29cf72SStephen Hemminger 989fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 990fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 9911da177e4SLinus Torvalds return count; 9921da177e4SLinus Torvalds } 99343d28b65SDaniel Turull if (!strcmp(name, "rate")) { 99443d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 99543d28b65SDaniel Turull if (len < 0) 99643d28b65SDaniel Turull return len; 99743d28b65SDaniel Turull 99843d28b65SDaniel Turull i += len; 99943d28b65SDaniel Turull if (!value) 100043d28b65SDaniel Turull return len; 100143d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 100243d28b65SDaniel Turull if (debug) 1003f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 100443d28b65SDaniel Turull 100543d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 100643d28b65SDaniel Turull return count; 100743d28b65SDaniel Turull } 100843d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 100943d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 101043d28b65SDaniel Turull if (len < 0) 101143d28b65SDaniel Turull return len; 101243d28b65SDaniel Turull 101343d28b65SDaniel Turull i += len; 101443d28b65SDaniel Turull if (!value) 101543d28b65SDaniel Turull return len; 101643d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 101743d28b65SDaniel Turull if (debug) 1018f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 101943d28b65SDaniel Turull 102043d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 102143d28b65SDaniel Turull return count; 102243d28b65SDaniel Turull } 10231da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10241da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 102563adc6fbSStephen Hemminger if (len < 0) 1026222f1806SLuiz Capitulino return len; 102763adc6fbSStephen Hemminger 10281da177e4SLinus Torvalds i += len; 10291da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10301da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10311da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10321da177e4SLinus Torvalds } 10331da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10341da177e4SLinus Torvalds return count; 10351da177e4SLinus Torvalds } 10361da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10371da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 103863adc6fbSStephen Hemminger if (len < 0) 1039222f1806SLuiz Capitulino return len; 104063adc6fbSStephen Hemminger 10411da177e4SLinus Torvalds i += len; 10421da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10431da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10441da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10471da177e4SLinus Torvalds return count; 10481da177e4SLinus Torvalds } 10491da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10501da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 105163adc6fbSStephen Hemminger if (len < 0) 1052222f1806SLuiz Capitulino return len; 105363adc6fbSStephen Hemminger 10541da177e4SLinus Torvalds i += len; 10551da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10561da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10571da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10581da177e4SLinus Torvalds } 10591da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10601da177e4SLinus Torvalds return count; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10631da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 106463adc6fbSStephen Hemminger if (len < 0) 1065222f1806SLuiz Capitulino return len; 106663adc6fbSStephen Hemminger 10671da177e4SLinus Torvalds i += len; 10681da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10691da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10701da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10731da177e4SLinus Torvalds return count; 10741da177e4SLinus Torvalds } 10751da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10761da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107763adc6fbSStephen Hemminger if (len < 0) 1078222f1806SLuiz Capitulino return len; 1079d8873315SNeil Horman if ((value > 0) && 1080d8873315SNeil Horman (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) 1081d8873315SNeil Horman return -ENOTSUPP; 10821da177e4SLinus Torvalds i += len; 10831da177e4SLinus Torvalds pkt_dev->clone_skb = value; 10841da177e4SLinus Torvalds 10851da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10861da177e4SLinus Torvalds return count; 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds if (!strcmp(name, "count")) { 10891da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109063adc6fbSStephen Hemminger if (len < 0) 1091222f1806SLuiz Capitulino return len; 109263adc6fbSStephen Hemminger 10931da177e4SLinus Torvalds i += len; 10941da177e4SLinus Torvalds pkt_dev->count = value; 10951da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 10961da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 10971da177e4SLinus Torvalds return count; 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 11001da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 110163adc6fbSStephen Hemminger if (len < 0) 1102222f1806SLuiz Capitulino return len; 110363adc6fbSStephen Hemminger 11041da177e4SLinus Torvalds i += len; 11051da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 11061da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11071da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11081da177e4SLinus Torvalds } 1109222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1110222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11111da177e4SLinus Torvalds return count; 11121da177e4SLinus Torvalds } 11131da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11141da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 111563adc6fbSStephen Hemminger if (len < 0) 1116222f1806SLuiz Capitulino return len; 111763adc6fbSStephen Hemminger 11181da177e4SLinus Torvalds i += len; 11191da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11201da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11211da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11221da177e4SLinus Torvalds } 1123222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1124222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11251da177e4SLinus Torvalds return count; 11261da177e4SLinus Torvalds } 1127e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1128e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1129e99b99b4SRobert Olsson if (len < 0) 1130e99b99b4SRobert Olsson return len; 1131e99b99b4SRobert Olsson 1132e99b99b4SRobert Olsson i += len; 1133e99b99b4SRobert Olsson 1134e99b99b4SRobert Olsson if (node_possible(value)) { 1135e99b99b4SRobert Olsson pkt_dev->node = value; 1136e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 113726ad7879SEric Dumazet if (pkt_dev->page) { 113826ad7879SEric Dumazet put_page(pkt_dev->page); 113926ad7879SEric Dumazet pkt_dev->page = NULL; 114026ad7879SEric Dumazet } 1141e99b99b4SRobert Olsson } 1142e99b99b4SRobert Olsson else 1143e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1144e99b99b4SRobert Olsson return count; 1145e99b99b4SRobert Olsson } 11461da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 11471da177e4SLinus Torvalds char f[32]; 11481da177e4SLinus Torvalds memset(f, 0, 32); 11491da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 115063adc6fbSStephen Hemminger if (len < 0) 1151222f1806SLuiz Capitulino return len; 115263adc6fbSStephen Hemminger 11531da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 11541da177e4SLinus Torvalds return -EFAULT; 11551da177e4SLinus Torvalds i += len; 11561da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 11571da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 11601da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 11631da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 11661da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 11691da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 11721da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 11751da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 11781da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 11811da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 11841da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 11871da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 11901da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 11911da177e4SLinus Torvalds 11921da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 11931da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 11961da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 11971da177e4SLinus Torvalds 1198ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1199ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1200ca6549afSSteven Whitehouse 1201ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1202ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1203ca6549afSSteven Whitehouse 120434954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 120534954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 120634954ddcSFrancesco Fondelli 120734954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 120834954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 120934954ddcSFrancesco Fondelli 121034954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 121134954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 121234954ddcSFrancesco Fondelli 121334954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 121434954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 121534954ddcSFrancesco Fondelli 1216007a531bSJamal Hadi Salim else if (strcmp(f, "FLOW_SEQ") == 0) 1217007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1218007a531bSJamal Hadi Salim 121945b270f8SRobert Olsson else if (strcmp(f, "QUEUE_MAP_RND") == 0) 122045b270f8SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_RND; 122145b270f8SRobert Olsson 122245b270f8SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_RND") == 0) 122345b270f8SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_RND; 1224e6fce5b9SRobert Olsson 1225e6fce5b9SRobert Olsson else if (strcmp(f, "QUEUE_MAP_CPU") == 0) 1226e6fce5b9SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_CPU; 1227e6fce5b9SRobert Olsson 1228e6fce5b9SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_CPU") == 0) 1229e6fce5b9SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_CPU; 1230a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1231a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1232a553e4a6SJamal Hadi Salim pkt_dev->flags |= F_IPSEC_ON; 1233a553e4a6SJamal Hadi Salim #endif 1234a553e4a6SJamal Hadi Salim 12351ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 12361ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 12371ca7768cSFrancesco Fondelli 1238e99b99b4SRobert Olsson else if (strcmp(f, "NODE_ALLOC") == 0) 1239e99b99b4SRobert Olsson pkt_dev->flags |= F_NODE; 1240e99b99b4SRobert Olsson 1241e99b99b4SRobert Olsson else if (strcmp(f, "!NODE_ALLOC") == 0) 1242e99b99b4SRobert Olsson pkt_dev->flags &= ~F_NODE; 1243e99b99b4SRobert Olsson 1244c26bf4a5SThomas Graf else if (strcmp(f, "UDPCSUM") == 0) 1245c26bf4a5SThomas Graf pkt_dev->flags |= F_UDPCSUM; 1246c26bf4a5SThomas Graf 1247c26bf4a5SThomas Graf else if (strcmp(f, "!UDPCSUM") == 0) 1248c26bf4a5SThomas Graf pkt_dev->flags &= ~F_UDPCSUM; 1249c26bf4a5SThomas Graf 1250afb84b62SJesper Dangaard Brouer else if (strcmp(f, "NO_TIMESTAMP") == 0) 1251afb84b62SJesper Dangaard Brouer pkt_dev->flags |= F_NO_TIMESTAMP; 1252afb84b62SJesper Dangaard Brouer 12531da177e4SLinus Torvalds else { 1254222f1806SLuiz Capitulino sprintf(pg_result, 1255222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12561da177e4SLinus Torvalds f, 12571ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 125872f8e06fSMathias Krause "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, " 125972f8e06fSMathias Krause "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, " 126072f8e06fSMathias Krause "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, " 1261afb84b62SJesper Dangaard Brouer "NO_TIMESTAMP, " 126272f8e06fSMathias Krause #ifdef CONFIG_XFRM 126372f8e06fSMathias Krause "IPSEC, " 126472f8e06fSMathias Krause #endif 126572f8e06fSMathias Krause "NODE_ALLOC\n"); 12661da177e4SLinus Torvalds return count; 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12691da177e4SLinus Torvalds return count; 12701da177e4SLinus Torvalds } 12711da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12721da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 127363adc6fbSStephen Hemminger if (len < 0) 1274222f1806SLuiz Capitulino return len; 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12771da177e4SLinus Torvalds return -EFAULT; 12781da177e4SLinus Torvalds buf[len] = 0; 12791da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12801da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12811da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 12821da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12831da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12841da177e4SLinus Torvalds } 12851da177e4SLinus Torvalds if (debug) 1286f342cda7SJoe Perches pr_debug("dst_min set to: %s\n", pkt_dev->dst_min); 12871da177e4SLinus Torvalds i += len; 12881da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12891da177e4SLinus Torvalds return count; 12901da177e4SLinus Torvalds } 12911da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12921da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 129363adc6fbSStephen Hemminger if (len < 0) 1294222f1806SLuiz Capitulino return len; 129563adc6fbSStephen Hemminger 12961da177e4SLinus Torvalds 12971da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12981da177e4SLinus Torvalds return -EFAULT; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds buf[len] = 0; 13011da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 13021da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 13031da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 13041da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 13051da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 13061da177e4SLinus Torvalds } 13071da177e4SLinus Torvalds if (debug) 1308f342cda7SJoe Perches pr_debug("dst_max set to: %s\n", pkt_dev->dst_max); 13091da177e4SLinus Torvalds i += len; 13101da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 13111da177e4SLinus Torvalds return count; 13121da177e4SLinus Torvalds } 13131da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 13141da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1315222f1806SLuiz Capitulino if (len < 0) 1316222f1806SLuiz Capitulino return len; 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13191da177e4SLinus Torvalds 13201da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13211da177e4SLinus Torvalds return -EFAULT; 13221da177e4SLinus Torvalds buf[len] = 0; 13231da177e4SLinus Torvalds 1324c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL); 132547a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); 13261da177e4SLinus Torvalds 13274e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr; 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds if (debug) 1330f342cda7SJoe Perches pr_debug("dst6 set to: %s\n", buf); 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds i += len; 13331da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13341da177e4SLinus Torvalds return count; 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13371da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1338222f1806SLuiz Capitulino if (len < 0) 1339222f1806SLuiz Capitulino return len; 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13441da177e4SLinus Torvalds return -EFAULT; 13451da177e4SLinus Torvalds buf[len] = 0; 13461da177e4SLinus Torvalds 1347c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL); 134847a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); 13491da177e4SLinus Torvalds 13504e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr; 13511da177e4SLinus Torvalds if (debug) 1352f342cda7SJoe Perches pr_debug("dst6_min set to: %s\n", buf); 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds i += len; 13551da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13561da177e4SLinus Torvalds return count; 13571da177e4SLinus Torvalds } 13581da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13591da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1360222f1806SLuiz Capitulino if (len < 0) 1361222f1806SLuiz Capitulino return len; 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13661da177e4SLinus Torvalds return -EFAULT; 13671da177e4SLinus Torvalds buf[len] = 0; 13681da177e4SLinus Torvalds 1369c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL); 137047a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); 13711da177e4SLinus Torvalds 13721da177e4SLinus Torvalds if (debug) 1373f342cda7SJoe Perches pr_debug("dst6_max set to: %s\n", buf); 13741da177e4SLinus Torvalds 13751da177e4SLinus Torvalds i += len; 13761da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13771da177e4SLinus Torvalds return count; 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13801da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1381222f1806SLuiz Capitulino if (len < 0) 1382222f1806SLuiz Capitulino return len; 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13871da177e4SLinus Torvalds return -EFAULT; 13881da177e4SLinus Torvalds buf[len] = 0; 13891da177e4SLinus Torvalds 1390c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL); 139147a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); 13921da177e4SLinus Torvalds 13934e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr; 13941da177e4SLinus Torvalds 13951da177e4SLinus Torvalds if (debug) 1396f342cda7SJoe Perches pr_debug("src6 set to: %s\n", buf); 13971da177e4SLinus Torvalds 13981da177e4SLinus Torvalds i += len; 13991da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 14001da177e4SLinus Torvalds return count; 14011da177e4SLinus Torvalds } 14021da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 14031da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 140463adc6fbSStephen Hemminger if (len < 0) 1405222f1806SLuiz Capitulino return len; 140663adc6fbSStephen Hemminger 14071da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14081da177e4SLinus Torvalds return -EFAULT; 14091da177e4SLinus Torvalds buf[len] = 0; 14101da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 14111da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 14121da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 14131da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 14141da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 14151da177e4SLinus Torvalds } 14161da177e4SLinus Torvalds if (debug) 1417f342cda7SJoe Perches pr_debug("src_min set to: %s\n", pkt_dev->src_min); 14181da177e4SLinus Torvalds i += len; 14191da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 14201da177e4SLinus Torvalds return count; 14211da177e4SLinus Torvalds } 14221da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 14231da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 142463adc6fbSStephen Hemminger if (len < 0) 1425222f1806SLuiz Capitulino return len; 142663adc6fbSStephen Hemminger 14271da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14281da177e4SLinus Torvalds return -EFAULT; 14291da177e4SLinus Torvalds buf[len] = 0; 14301da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14311da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14321da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 14331da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14341da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14351da177e4SLinus Torvalds } 14361da177e4SLinus Torvalds if (debug) 1437f342cda7SJoe Perches pr_debug("src_max set to: %s\n", pkt_dev->src_max); 14381da177e4SLinus Torvalds i += len; 14391da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14401da177e4SLinus Torvalds return count; 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14431da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 144463adc6fbSStephen Hemminger if (len < 0) 1445222f1806SLuiz Capitulino return len; 144663adc6fbSStephen Hemminger 14471da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14481da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14491da177e4SLinus Torvalds return -EFAULT; 14501da177e4SLinus Torvalds 14514940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->dst_mac)) 14524940fc88SAlexey Dobriyan return -EINVAL; 14531da177e4SLinus Torvalds /* Set up Dest MAC */ 14549ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); 14551da177e4SLinus Torvalds 14564940fc88SAlexey Dobriyan sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); 14571da177e4SLinus Torvalds return count; 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14601da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 146163adc6fbSStephen Hemminger if (len < 0) 1462222f1806SLuiz Capitulino return len; 146363adc6fbSStephen Hemminger 14641da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14651da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14661da177e4SLinus Torvalds return -EFAULT; 14671da177e4SLinus Torvalds 14684940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->src_mac)) 14694940fc88SAlexey Dobriyan return -EINVAL; 1470ce5d0b47SAdit Ranadive /* Set up Src MAC */ 14719ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); 1472ce5d0b47SAdit Ranadive 14734940fc88SAlexey Dobriyan sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); 14741da177e4SLinus Torvalds return count; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 14781da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 14791da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 14801da177e4SLinus Torvalds return count; 14811da177e4SLinus Torvalds } 14821da177e4SLinus Torvalds 14831da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 14841da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 148563adc6fbSStephen Hemminger if (len < 0) 1486222f1806SLuiz Capitulino return len; 148763adc6fbSStephen Hemminger 14881da177e4SLinus Torvalds i += len; 14891da177e4SLinus Torvalds if (value > MAX_CFLOWS) 14901da177e4SLinus Torvalds value = MAX_CFLOWS; 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds pkt_dev->cflows = value; 14931da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 14941da177e4SLinus Torvalds return count; 14951da177e4SLinus Torvalds } 14966bae9190SFan Du #ifdef CONFIG_XFRM 1497de4aee7dSFan Du if (!strcmp(name, "spi")) { 1498de4aee7dSFan Du len = num_arg(&user_buffer[i], 10, &value); 1499de4aee7dSFan Du if (len < 0) 1500de4aee7dSFan Du return len; 1501de4aee7dSFan Du 1502de4aee7dSFan Du i += len; 1503de4aee7dSFan Du pkt_dev->spi = value; 1504de4aee7dSFan Du sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); 1505de4aee7dSFan Du return count; 1506de4aee7dSFan Du } 15076bae9190SFan Du #endif 15081da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15091da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 151063adc6fbSStephen Hemminger if (len < 0) 1511222f1806SLuiz Capitulino return len; 151263adc6fbSStephen Hemminger 15131da177e4SLinus Torvalds i += len; 15141da177e4SLinus Torvalds pkt_dev->lflow = value; 15151da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 15161da177e4SLinus Torvalds return count; 15171da177e4SLinus Torvalds } 15181da177e4SLinus Torvalds 151945b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 152045b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 152163adc6fbSStephen Hemminger if (len < 0) 152245b270f8SRobert Olsson return len; 152363adc6fbSStephen Hemminger 152445b270f8SRobert Olsson i += len; 152545b270f8SRobert Olsson pkt_dev->queue_map_min = value; 152645b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 152745b270f8SRobert Olsson return count; 152845b270f8SRobert Olsson } 152945b270f8SRobert Olsson 153045b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 153145b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 153263adc6fbSStephen Hemminger if (len < 0) 153345b270f8SRobert Olsson return len; 153463adc6fbSStephen Hemminger 153545b270f8SRobert Olsson i += len; 153645b270f8SRobert Olsson pkt_dev->queue_map_max = value; 153745b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 153845b270f8SRobert Olsson return count; 153945b270f8SRobert Olsson } 154045b270f8SRobert Olsson 1541ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 154295c96174SEric Dumazet unsigned int n, cnt; 1543cfcabdccSStephen Hemminger 1544ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1545cfcabdccSStephen Hemminger if (len < 0) 1546cfcabdccSStephen Hemminger return len; 1547ca6549afSSteven Whitehouse i += len; 1548cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1549ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1550cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1551ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1552ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 155334954ddcSFrancesco Fondelli 155434954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 155534954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 155634954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 155734954ddcSFrancesco Fondelli 155834954ddcSFrancesco Fondelli if (debug) 1559f342cda7SJoe Perches pr_debug("VLAN/SVLAN auto turned off\n"); 156034954ddcSFrancesco Fondelli } 156134954ddcSFrancesco Fondelli return count; 156234954ddcSFrancesco Fondelli } 156334954ddcSFrancesco Fondelli 156434954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 156534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 156663adc6fbSStephen Hemminger if (len < 0) 156734954ddcSFrancesco Fondelli return len; 156863adc6fbSStephen Hemminger 156934954ddcSFrancesco Fondelli i += len; 157034954ddcSFrancesco Fondelli if (value <= 4095) { 157134954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 157234954ddcSFrancesco Fondelli 157334954ddcSFrancesco Fondelli if (debug) 1574f342cda7SJoe Perches pr_debug("VLAN turned on\n"); 157534954ddcSFrancesco Fondelli 157634954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1577f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 157834954ddcSFrancesco Fondelli 157934954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 158034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 158134954ddcSFrancesco Fondelli } else { 158234954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 158334954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 158434954ddcSFrancesco Fondelli 158534954ddcSFrancesco Fondelli if (debug) 1586f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 158734954ddcSFrancesco Fondelli } 158834954ddcSFrancesco Fondelli return count; 158934954ddcSFrancesco Fondelli } 159034954ddcSFrancesco Fondelli 159134954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 159234954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 159363adc6fbSStephen Hemminger if (len < 0) 159434954ddcSFrancesco Fondelli return len; 159563adc6fbSStephen Hemminger 159634954ddcSFrancesco Fondelli i += len; 159734954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 159834954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 159934954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 160034954ddcSFrancesco Fondelli } else { 160134954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 160234954ddcSFrancesco Fondelli } 160334954ddcSFrancesco Fondelli return count; 160434954ddcSFrancesco Fondelli } 160534954ddcSFrancesco Fondelli 160634954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 160734954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 160863adc6fbSStephen Hemminger if (len < 0) 160934954ddcSFrancesco Fondelli return len; 161063adc6fbSStephen Hemminger 161134954ddcSFrancesco Fondelli i += len; 161234954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 161334954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 161434954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 161534954ddcSFrancesco Fondelli } else { 161634954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 161734954ddcSFrancesco Fondelli } 161834954ddcSFrancesco Fondelli return count; 161934954ddcSFrancesco Fondelli } 162034954ddcSFrancesco Fondelli 162134954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 162234954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 162363adc6fbSStephen Hemminger if (len < 0) 162434954ddcSFrancesco Fondelli return len; 162563adc6fbSStephen Hemminger 162634954ddcSFrancesco Fondelli i += len; 162734954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 162834954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 162934954ddcSFrancesco Fondelli 163034954ddcSFrancesco Fondelli if (debug) 1631f342cda7SJoe Perches pr_debug("SVLAN turned on\n"); 163234954ddcSFrancesco Fondelli 163334954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1634f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 163534954ddcSFrancesco Fondelli 163634954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 163734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 163834954ddcSFrancesco Fondelli } else { 163934954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 164034954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 164134954ddcSFrancesco Fondelli 164234954ddcSFrancesco Fondelli if (debug) 1643f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 164434954ddcSFrancesco Fondelli } 164534954ddcSFrancesco Fondelli return count; 164634954ddcSFrancesco Fondelli } 164734954ddcSFrancesco Fondelli 164834954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 164934954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 165063adc6fbSStephen Hemminger if (len < 0) 165134954ddcSFrancesco Fondelli return len; 165263adc6fbSStephen Hemminger 165334954ddcSFrancesco Fondelli i += len; 165434954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 165534954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 165634954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 165734954ddcSFrancesco Fondelli } else { 165834954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 165934954ddcSFrancesco Fondelli } 166034954ddcSFrancesco Fondelli return count; 166134954ddcSFrancesco Fondelli } 166234954ddcSFrancesco Fondelli 166334954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 166434954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 166563adc6fbSStephen Hemminger if (len < 0) 166634954ddcSFrancesco Fondelli return len; 166763adc6fbSStephen Hemminger 166834954ddcSFrancesco Fondelli i += len; 166934954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 167034954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 167134954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 167234954ddcSFrancesco Fondelli } else { 167334954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 167434954ddcSFrancesco Fondelli } 1675ca6549afSSteven Whitehouse return count; 1676ca6549afSSteven Whitehouse } 1677ca6549afSSteven Whitehouse 16781ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16791ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16801ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 168163adc6fbSStephen Hemminger if (len < 0) 16821ca7768cSFrancesco Fondelli return len; 168363adc6fbSStephen Hemminger 16841ca7768cSFrancesco Fondelli i += len; 16851ca7768cSFrancesco Fondelli if (len == 2) { 16861ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16871ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16881ca7768cSFrancesco Fondelli } else { 16891ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 16901ca7768cSFrancesco Fondelli } 16911ca7768cSFrancesco Fondelli return count; 16921ca7768cSFrancesco Fondelli } 16931ca7768cSFrancesco Fondelli 16941ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 16951ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16961ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 169763adc6fbSStephen Hemminger if (len < 0) 16981ca7768cSFrancesco Fondelli return len; 169963adc6fbSStephen Hemminger 17001ca7768cSFrancesco Fondelli i += len; 17011ca7768cSFrancesco Fondelli if (len == 2) { 17021ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17031ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17041ca7768cSFrancesco Fondelli } else { 17051ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17061ca7768cSFrancesco Fondelli } 17071ca7768cSFrancesco Fondelli return count; 17081ca7768cSFrancesco Fondelli } 17091ca7768cSFrancesco Fondelli 17109e50e3acSJohn Fastabend if (!strcmp(name, "skb_priority")) { 17119e50e3acSJohn Fastabend len = num_arg(&user_buffer[i], 9, &value); 17129e50e3acSJohn Fastabend if (len < 0) 17139e50e3acSJohn Fastabend return len; 17149e50e3acSJohn Fastabend 17159e50e3acSJohn Fastabend i += len; 17169e50e3acSJohn Fastabend pkt_dev->skb_priority = value; 17179e50e3acSJohn Fastabend sprintf(pg_result, "OK: skb_priority=%i", 17189e50e3acSJohn Fastabend pkt_dev->skb_priority); 17199e50e3acSJohn Fastabend return count; 17209e50e3acSJohn Fastabend } 17219e50e3acSJohn Fastabend 17221da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 17231da177e4SLinus Torvalds return -EINVAL; 17241da177e4SLinus Torvalds } 17251da177e4SLinus Torvalds 1726d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17271da177e4SLinus Torvalds { 1728d9dda78bSAl Viro return single_open(file, pktgen_if_show, PDE_DATA(inode)); 17291da177e4SLinus Torvalds } 17301da177e4SLinus Torvalds 17319a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1732d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1733d50a6b56SStephen Hemminger .open = pktgen_if_open, 1734d50a6b56SStephen Hemminger .read = seq_read, 1735d50a6b56SStephen Hemminger .llseek = seq_lseek, 1736d50a6b56SStephen Hemminger .write = pktgen_if_write, 1737d50a6b56SStephen Hemminger .release = single_release, 1738d50a6b56SStephen Hemminger }; 1739d50a6b56SStephen Hemminger 1740d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1741d50a6b56SStephen Hemminger { 1742d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1743648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1744d50a6b56SStephen Hemminger 1745d50a6b56SStephen Hemminger BUG_ON(!t); 1746d50a6b56SStephen Hemminger 174797dc48e2SThomas Graf seq_puts(seq, "Running: "); 17481da177e4SLinus Torvalds 17498788370aSJesper Dangaard Brouer rcu_read_lock(); 17508788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 17511da177e4SLinus Torvalds if (pkt_dev->running) 1752593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17531da177e4SLinus Torvalds 175497dc48e2SThomas Graf seq_puts(seq, "\nStopped: "); 17551da177e4SLinus Torvalds 17568788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 17571da177e4SLinus Torvalds if (!pkt_dev->running) 1758593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17591da177e4SLinus Torvalds 17601da177e4SLinus Torvalds if (t->result[0]) 1761d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17621da177e4SLinus Torvalds else 176397dc48e2SThomas Graf seq_puts(seq, "\nResult: NA\n"); 17641da177e4SLinus Torvalds 17658788370aSJesper Dangaard Brouer rcu_read_unlock(); 17661da177e4SLinus Torvalds 1767d50a6b56SStephen Hemminger return 0; 17681da177e4SLinus Torvalds } 17691da177e4SLinus Torvalds 1770d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1771d50a6b56SStephen Hemminger const char __user * user_buffer, 1772d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17731da177e4SLinus Torvalds { 17748a994a71SJoe Perches struct seq_file *seq = file->private_data; 1775d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1776d6182223SPaul Gortmaker int i, max, len, ret; 17771da177e4SLinus Torvalds char name[40]; 17781da177e4SLinus Torvalds char *pg_result; 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds if (count < 1) { 17811da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17821da177e4SLinus Torvalds return -EINVAL; 17831da177e4SLinus Torvalds } 17841da177e4SLinus Torvalds 1785d6182223SPaul Gortmaker max = count; 1786d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 17871da177e4SLinus Torvalds if (len < 0) 17881da177e4SLinus Torvalds return len; 17891da177e4SLinus Torvalds 1790d6182223SPaul Gortmaker i = len; 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds /* Read variable name */ 17931da177e4SLinus Torvalds 17941da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 17951da177e4SLinus Torvalds if (len < 0) 17961da177e4SLinus Torvalds return len; 17971da177e4SLinus Torvalds 17981da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 17991da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 18001da177e4SLinus Torvalds return -EFAULT; 18011da177e4SLinus Torvalds i += len; 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds max = count - i; 18041da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 18051da177e4SLinus Torvalds if (len < 0) 18061da177e4SLinus Torvalds return len; 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds i += len; 18091da177e4SLinus Torvalds 18101da177e4SLinus Torvalds if (debug) 1811f342cda7SJoe Perches pr_debug("t=%s, count=%lu\n", name, (unsigned long)count); 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds if (!t) { 1814f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 18151da177e4SLinus Torvalds ret = -EINVAL; 18161da177e4SLinus Torvalds goto out; 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds pg_result = &(t->result[0]); 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 18221da177e4SLinus Torvalds char f[32]; 18231da177e4SLinus Torvalds memset(f, 0, 32); 18241da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18251da177e4SLinus Torvalds if (len < 0) { 18261da177e4SLinus Torvalds ret = len; 18271da177e4SLinus Torvalds goto out; 18281da177e4SLinus Torvalds } 18291da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18301da177e4SLinus Torvalds return -EFAULT; 18311da177e4SLinus Torvalds i += len; 18326146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1833604dfd6eSCong Wang ret = pktgen_add_device(t, f); 18346146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1835604dfd6eSCong Wang if (!ret) { 18361da177e4SLinus Torvalds ret = count; 18371da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 1838604dfd6eSCong Wang } else 1839604dfd6eSCong Wang sprintf(pg_result, "ERROR: can not add device %s", f); 18401da177e4SLinus Torvalds goto out; 18411da177e4SLinus Torvalds } 18421da177e4SLinus Torvalds 18431da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18446146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 184595ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18466146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1847121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18481da177e4SLinus Torvalds ret = count; 18491da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18501da177e4SLinus Torvalds goto out; 18511da177e4SLinus Torvalds } 18521da177e4SLinus Torvalds 18531da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1854b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18551da177e4SLinus Torvalds ret = count; 18561da177e4SLinus Torvalds goto out; 18571da177e4SLinus Torvalds } 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds ret = -EINVAL; 18601da177e4SLinus Torvalds out: 18611da177e4SLinus Torvalds return ret; 18621da177e4SLinus Torvalds } 18631da177e4SLinus Torvalds 1864d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18651da177e4SLinus Torvalds { 1866d9dda78bSAl Viro return single_open(file, pktgen_thread_show, PDE_DATA(inode)); 18671da177e4SLinus Torvalds } 18681da177e4SLinus Torvalds 18699a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1870d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1871d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1872d50a6b56SStephen Hemminger .read = seq_read, 1873d50a6b56SStephen Hemminger .llseek = seq_lseek, 1874d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1875d50a6b56SStephen Hemminger .release = single_release, 1876d50a6b56SStephen Hemminger }; 18771da177e4SLinus Torvalds 18781da177e4SLinus Torvalds /* Think find or remove for NN */ 18794e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, 18804e58a027SCong Wang const char *ifname, int remove) 18811da177e4SLinus Torvalds { 18821da177e4SLinus Torvalds struct pktgen_thread *t; 18831da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18843e984840SEric Dumazet bool exact = (remove == FIND); 18851da177e4SLinus Torvalds 18864e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 18873e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 18881da177e4SLinus Torvalds if (pkt_dev) { 18891da177e4SLinus Torvalds if (remove) { 189095ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 189195ed63f7SArthur Kepner t->control |= T_REMDEV; 18921da177e4SLinus Torvalds } 18931da177e4SLinus Torvalds break; 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds } 18961da177e4SLinus Torvalds return pkt_dev; 18971da177e4SLinus Torvalds } 18981da177e4SLinus Torvalds 189995ed63f7SArthur Kepner /* 190095ed63f7SArthur Kepner * mark a device for removal 190195ed63f7SArthur Kepner */ 19024e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname) 19031da177e4SLinus Torvalds { 19041da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 190595ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 190695ed63f7SArthur Kepner int i = 0; 190795ed63f7SArthur Kepner 19086146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1909f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 191095ed63f7SArthur Kepner 191195ed63f7SArthur Kepner while (1) { 191295ed63f7SArthur Kepner 19134e58a027SCong Wang pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE); 1914222f1806SLuiz Capitulino if (pkt_dev == NULL) 1915222f1806SLuiz Capitulino break; /* success */ 191695ed63f7SArthur Kepner 19176146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1918f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 1919f9467eaeSJoe Perches __func__, ifname); 192095ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 19216146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 192295ed63f7SArthur Kepner 192395ed63f7SArthur Kepner if (++i >= max_tries) { 1924f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 1925f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 192695ed63f7SArthur Kepner break; 192795ed63f7SArthur Kepner } 192895ed63f7SArthur Kepner 192995ed63f7SArthur Kepner } 193095ed63f7SArthur Kepner 19316146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 193239df232fSStephen Hemminger } 193395ed63f7SArthur Kepner 19344e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) 193539df232fSStephen Hemminger { 193639df232fSStephen Hemminger struct pktgen_thread *t; 193739df232fSStephen Hemminger 19384e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 193939df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 194039df232fSStephen Hemminger 19418788370aSJesper Dangaard Brouer rcu_read_lock(); 19428788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 194339df232fSStephen Hemminger if (pkt_dev->odev != dev) 194439df232fSStephen Hemminger continue; 194539df232fSStephen Hemminger 1946a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 194739df232fSStephen Hemminger 19482975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 19494e58a027SCong Wang pn->proc_dir, 19502975315bSAlexey Dobriyan &pktgen_if_fops, 19512975315bSAlexey Dobriyan pkt_dev); 195239df232fSStephen Hemminger if (!pkt_dev->entry) 1953f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 1954f9467eaeSJoe Perches dev->name); 195539df232fSStephen Hemminger break; 195639df232fSStephen Hemminger } 19578788370aSJesper Dangaard Brouer rcu_read_unlock(); 195839df232fSStephen Hemminger } 19591da177e4SLinus Torvalds } 19601da177e4SLinus Torvalds 1961222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1962222f1806SLuiz Capitulino unsigned long event, void *ptr) 19631da177e4SLinus Torvalds { 1964351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 19654e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id); 19661da177e4SLinus Torvalds 19674e58a027SCong Wang if (pn->pktgen_exiting) 1968e9dc8653SEric W. Biederman return NOTIFY_DONE; 1969e9dc8653SEric W. Biederman 19701da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19711da177e4SLinus Torvalds * as we run under the RTNL lock. 19721da177e4SLinus Torvalds */ 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds switch (event) { 197539df232fSStephen Hemminger case NETDEV_CHANGENAME: 19764e58a027SCong Wang pktgen_change_name(pn, dev); 19771da177e4SLinus Torvalds break; 19781da177e4SLinus Torvalds 19791da177e4SLinus Torvalds case NETDEV_UNREGISTER: 19804e58a027SCong Wang pktgen_mark_device(pn, dev->name); 19811da177e4SLinus Torvalds break; 19823ff50b79SStephen Hemminger } 19831da177e4SLinus Torvalds 19841da177e4SLinus Torvalds return NOTIFY_DONE; 19851da177e4SLinus Torvalds } 19861da177e4SLinus Torvalds 19874e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn, 19884e58a027SCong Wang struct pktgen_dev *pkt_dev, 198963adc6fbSStephen Hemminger const char *ifname) 1990e6fce5b9SRobert Olsson { 1991e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 1992d6182223SPaul Gortmaker int i; 1993e6fce5b9SRobert Olsson 1994e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 1995e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 1996e6fce5b9SRobert Olsson break; 1997e6fce5b9SRobert Olsson 1998e6fce5b9SRobert Olsson b[i] = ifname[i]; 1999e6fce5b9SRobert Olsson } 2000e6fce5b9SRobert Olsson b[i] = 0; 2001e6fce5b9SRobert Olsson 20024e58a027SCong Wang return dev_get_by_name(pn->net, b); 2003e6fce5b9SRobert Olsson } 2004e6fce5b9SRobert Olsson 2005e6fce5b9SRobert Olsson 20061da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 20071da177e4SLinus Torvalds 20084e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn, 20094e58a027SCong Wang struct pktgen_dev *pkt_dev, const char *ifname) 2010222f1806SLuiz Capitulino { 20111da177e4SLinus Torvalds struct net_device *odev; 201239df232fSStephen Hemminger int err; 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds /* Clean old setups */ 20151da177e4SLinus Torvalds if (pkt_dev->odev) { 20161da177e4SLinus Torvalds dev_put(pkt_dev->odev); 20171da177e4SLinus Torvalds pkt_dev->odev = NULL; 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds 20204e58a027SCong Wang odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname); 20211da177e4SLinus Torvalds if (!odev) { 2022f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 202339df232fSStephen Hemminger return -ENODEV; 20241da177e4SLinus Torvalds } 202539df232fSStephen Hemminger 20261da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 2027f9467eaeSJoe Perches pr_err("not an ethernet device: \"%s\"\n", ifname); 202839df232fSStephen Hemminger err = -EINVAL; 202939df232fSStephen Hemminger } else if (!netif_running(odev)) { 2030f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 203139df232fSStephen Hemminger err = -ENETDOWN; 203239df232fSStephen Hemminger } else { 20331da177e4SLinus Torvalds pkt_dev->odev = odev; 203439df232fSStephen Hemminger return 0; 203539df232fSStephen Hemminger } 20361da177e4SLinus Torvalds 20371da177e4SLinus Torvalds dev_put(odev); 203839df232fSStephen Hemminger return err; 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 20421da177e4SLinus Torvalds * structure to have the right information to create/send packets 20431da177e4SLinus Torvalds */ 20441da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20451da177e4SLinus Torvalds { 204664c00d81SAndrew Gallatin int ntxq; 204764c00d81SAndrew Gallatin 20481da177e4SLinus Torvalds if (!pkt_dev->odev) { 2049f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2050222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2051222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20521da177e4SLinus Torvalds return; 20531da177e4SLinus Torvalds } 20541da177e4SLinus Torvalds 205564c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 205664c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2057bfdbc0acSRobert Olsson 205864c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2059*294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 206088271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2061593f63b0SEric Dumazet pkt_dev->odevname); 206226e29eedSDan Carpenter pkt_dev->queue_map_min = (ntxq ?: 1) - 1; 206364c00d81SAndrew Gallatin } 206488271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2065*294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 206688271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2067593f63b0SEric Dumazet pkt_dev->odevname); 206826e29eedSDan Carpenter pkt_dev->queue_map_max = (ntxq ?: 1) - 1; 206964c00d81SAndrew Gallatin } 207064c00d81SAndrew Gallatin 20711da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20721da177e4SLinus Torvalds 2073f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 20749ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds /* Set up Dest MAC */ 20779ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); 20781da177e4SLinus Torvalds 20791da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20804c139b8cSAmerigo Wang int i, set = 0, err = 1; 20814c139b8cSAmerigo Wang struct inet6_dev *idev; 20824c139b8cSAmerigo Wang 208368bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 208468bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr) 208568bf9f0bSAmerigo Wang + sizeof(struct udphdr) 208668bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 208768bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 208868bf9f0bSAmerigo Wang } 208968bf9f0bSAmerigo Wang 20901da177e4SLinus Torvalds for (i = 0; i < IN6_ADDR_HSIZE; i++) 20911da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20921da177e4SLinus Torvalds set = 1; 20931da177e4SLinus Torvalds break; 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds 20961da177e4SLinus Torvalds if (!set) { 20971da177e4SLinus Torvalds 20981da177e4SLinus Torvalds /* 20991da177e4SLinus Torvalds * Use linklevel address if unconfigured. 21001da177e4SLinus Torvalds * 21011da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 21021da177e4SLinus Torvalds */ 21031da177e4SLinus Torvalds 21048814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 210563adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 210663adc6fbSStephen Hemminger if (idev) { 21071da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 21081da177e4SLinus Torvalds 21091da177e4SLinus Torvalds read_lock_bh(&idev->lock); 21104c139b8cSAmerigo Wang list_for_each_entry(ifp, &idev->addr_list, if_list) { 21114c139b8cSAmerigo Wang if ((ifp->scope & IFA_LINK) && 2112f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 21134e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = ifp->addr; 21141da177e4SLinus Torvalds err = 0; 21151da177e4SLinus Torvalds break; 21161da177e4SLinus Torvalds } 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 21191da177e4SLinus Torvalds } 21208814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2121222f1806SLuiz Capitulino if (err) 2122f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 21231da177e4SLinus Torvalds } 2124222f1806SLuiz Capitulino } else { 212568bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 212668bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr) 212768bf9f0bSAmerigo Wang + sizeof(struct udphdr) 212868bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 212968bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 213068bf9f0bSAmerigo Wang } 213168bf9f0bSAmerigo Wang 21321da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 21331da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 21341da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 21351da177e4SLinus Torvalds 21361da177e4SLinus Torvalds struct in_device *in_dev; 21371da177e4SLinus Torvalds 21381da177e4SLinus Torvalds rcu_read_lock(); 2139e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 21401da177e4SLinus Torvalds if (in_dev) { 21411da177e4SLinus Torvalds if (in_dev->ifa_list) { 2142222f1806SLuiz Capitulino pkt_dev->saddr_min = 2143222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 21441da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 21451da177e4SLinus Torvalds } 21461da177e4SLinus Torvalds } 21471da177e4SLinus Torvalds rcu_read_unlock(); 2148222f1806SLuiz Capitulino } else { 21491da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21501da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21511da177e4SLinus Torvalds } 21521da177e4SLinus Torvalds 21531da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21541da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21551da177e4SLinus Torvalds } 21561da177e4SLinus Torvalds /* Initialize current values. */ 215768bf9f0bSAmerigo Wang pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 215868bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size) 215968bf9f0bSAmerigo Wang pkt_dev->max_pkt_size = pkt_dev->min_pkt_size; 216068bf9f0bSAmerigo Wang 21611da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 21621da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 21631da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 21641da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 21651da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21661da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21671da177e4SLinus Torvalds pkt_dev->nflows = 0; 21681da177e4SLinus Torvalds } 21691da177e4SLinus Torvalds 21701da177e4SLinus Torvalds 2171fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2172fd29cf72SStephen Hemminger { 2173ef87979cSStephen Hemminger ktime_t start_time, end_time; 2174417bc4b8SEric Dumazet s64 remaining; 21752bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2176fd29cf72SStephen Hemminger 21772bc481cfSStephen Hemminger hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21782bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2179fd29cf72SStephen Hemminger 218043d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2181417bc4b8SEric Dumazet if (remaining <= 0) { 2182417bc4b8SEric Dumazet pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21831da177e4SLinus Torvalds return; 2184417bc4b8SEric Dumazet } 21852bc481cfSStephen Hemminger 2186398f382cSDaniel Borkmann start_time = ktime_get(); 218733136d12SEric Dumazet if (remaining < 100000) { 218833136d12SEric Dumazet /* for small delays (<100us), just loop until limit is reached */ 218933136d12SEric Dumazet do { 2190398f382cSDaniel Borkmann end_time = ktime_get(); 2191398f382cSDaniel Borkmann } while (ktime_compare(end_time, spin_until) < 0); 219233136d12SEric Dumazet } else { 21932bc481cfSStephen Hemminger /* see do_nanosleep */ 21942bc481cfSStephen Hemminger hrtimer_init_sleeper(&t, current); 21952bc481cfSStephen Hemminger do { 21962bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 21972bc481cfSStephen Hemminger hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); 21982bc481cfSStephen Hemminger if (!hrtimer_active(&t.timer)) 21992bc481cfSStephen Hemminger t.task = NULL; 22002bc481cfSStephen Hemminger 22012bc481cfSStephen Hemminger if (likely(t.task)) 22021da177e4SLinus Torvalds schedule(); 22031da177e4SLinus Torvalds 22042bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 22052bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 22062bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 2207398f382cSDaniel Borkmann end_time = ktime_get(); 220833136d12SEric Dumazet } 2209ef87979cSStephen Hemminger 2210ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 221107a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 22121da177e4SLinus Torvalds } 22131da177e4SLinus Torvalds 221416dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 221516dab72fSJamal Hadi Salim { 2216a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead = 0; 221716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 221816dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 221916dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 222016dab72fSJamal Hadi Salim } 222116dab72fSJamal Hadi Salim 2222648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2223007a531bSJamal Hadi Salim { 2224648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2225007a531bSJamal Hadi Salim } 2226007a531bSJamal Hadi Salim 2227007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2228007a531bSJamal Hadi Salim { 2229007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2230007a531bSJamal Hadi Salim 2231007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2232007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2233007a531bSJamal Hadi Salim /* reset time */ 2234007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22351211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2236007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2237007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2238007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2239007a531bSJamal Hadi Salim } 2240007a531bSJamal Hadi Salim } else { 224133d7c5e5SAkinobu Mita flow = prandom_u32() % pkt_dev->cflows; 22421211a645SRobert Olsson pkt_dev->curfl = flow; 2243007a531bSJamal Hadi Salim 22441211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2245007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22461211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 22471211a645SRobert Olsson } 2248007a531bSJamal Hadi Salim } 2249007a531bSJamal Hadi Salim 2250007a531bSJamal Hadi Salim return pkt_dev->curfl; 2251007a531bSJamal Hadi Salim } 2252007a531bSJamal Hadi Salim 2253a553e4a6SJamal Hadi Salim 2254a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2255a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2256a553e4a6SJamal Hadi Salim * we go look for it ... 2257a553e4a6SJamal Hadi Salim */ 2258bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2259fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2260a553e4a6SJamal Hadi Salim { 2261a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 22624e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); 2263a553e4a6SJamal Hadi Salim if (!x) { 2264c454997eSFan Du 2265c454997eSFan Du if (pkt_dev->spi) { 2266c454997eSFan Du /* We need as quick as possible to find the right SA 2267c454997eSFan Du * Searching with minimum criteria to archieve this. 2268c454997eSFan Du */ 2269c454997eSFan Du x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); 2270c454997eSFan Du } else { 2271a553e4a6SJamal Hadi Salim /* slow path: we dont already have xfrm_state */ 22724e58a027SCong Wang x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 22735447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2274a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2275a553e4a6SJamal Hadi Salim AF_INET, 2276a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2277a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2278c454997eSFan Du } 2279a553e4a6SJamal Hadi Salim if (x) { 2280a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2281a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2282a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2283a553e4a6SJamal Hadi Salim } 2284a553e4a6SJamal Hadi Salim 2285a553e4a6SJamal Hadi Salim } 2286a553e4a6SJamal Hadi Salim } 2287a553e4a6SJamal Hadi Salim #endif 2288fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2289fd2ea0a7SDavid S. Miller { 2290e6fce5b9SRobert Olsson 2291e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2292e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2293e6fce5b9SRobert Olsson 2294896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2295fd2ea0a7SDavid S. Miller __u16 t; 2296fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 229733d7c5e5SAkinobu Mita t = prandom_u32() % 2298fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2299fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2300fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2301fd2ea0a7SDavid S. Miller } else { 2302fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2303fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2304fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2305fd2ea0a7SDavid S. Miller } 2306fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2307fd2ea0a7SDavid S. Miller } 2308bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2309fd2ea0a7SDavid S. Miller } 2310fd2ea0a7SDavid S. Miller 23111da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 23121da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 23131da177e4SLinus Torvalds */ 2314222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2315222f1806SLuiz Capitulino { 23161da177e4SLinus Torvalds __u32 imn; 23171da177e4SLinus Torvalds __u32 imx; 23181da177e4SLinus Torvalds int flow = 0; 23191da177e4SLinus Torvalds 2320007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2321007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 23221da177e4SLinus Torvalds 23231da177e4SLinus Torvalds /* Deal with source MAC */ 23241da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 23251da177e4SLinus Torvalds __u32 mc; 23261da177e4SLinus Torvalds __u32 tmp; 23271da177e4SLinus Torvalds 23281da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 232933d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->src_mac_count; 23301da177e4SLinus Torvalds else { 23311da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2332ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2333222f1806SLuiz Capitulino pkt_dev->src_mac_count) 23341da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23381da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 23391da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23401da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 23411da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23421da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 23431da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23441da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 23451da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23461da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 23471da177e4SLinus Torvalds } 23481da177e4SLinus Torvalds 23491da177e4SLinus Torvalds /* Deal with Destination MAC */ 23501da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 23511da177e4SLinus Torvalds __u32 mc; 23521da177e4SLinus Torvalds __u32 tmp; 23531da177e4SLinus Torvalds 23541da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 235533d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->dst_mac_count; 23561da177e4SLinus Torvalds 23571da177e4SLinus Torvalds else { 23581da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2359ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2360222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 23611da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 23621da177e4SLinus Torvalds } 23631da177e4SLinus Torvalds } 23641da177e4SLinus Torvalds 23651da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23661da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 23671da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23681da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 23691da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23701da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 23711da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23721da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 23731da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23741da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 23751da177e4SLinus Torvalds } 23761da177e4SLinus Torvalds 2377ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 237895c96174SEric Dumazet unsigned int i; 2379ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2380ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2381ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 238233d7c5e5SAkinobu Mita ((__force __be32)prandom_u32() & 2383ca6549afSSteven Whitehouse htonl(0x000fffff)); 2384ca6549afSSteven Whitehouse } 2385ca6549afSSteven Whitehouse 238634954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 238733d7c5e5SAkinobu Mita pkt_dev->vlan_id = prandom_u32() & (4096 - 1); 238834954ddcSFrancesco Fondelli } 238934954ddcSFrancesco Fondelli 239034954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 239133d7c5e5SAkinobu Mita pkt_dev->svlan_id = prandom_u32() & (4096 - 1); 239234954ddcSFrancesco Fondelli } 239334954ddcSFrancesco Fondelli 23941da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23951da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 239633d7c5e5SAkinobu Mita pkt_dev->cur_udp_src = prandom_u32() % 23975fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23985fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 23991da177e4SLinus Torvalds 24001da177e4SLinus Torvalds else { 24011da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 24021da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 24031da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 24041da177e4SLinus Torvalds } 24051da177e4SLinus Torvalds } 24061da177e4SLinus Torvalds 24071da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 24081da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 240933d7c5e5SAkinobu Mita pkt_dev->cur_udp_dst = prandom_u32() % 24105fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 24115fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2412222f1806SLuiz Capitulino } else { 24131da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 24141da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 24151da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 24161da177e4SLinus Torvalds } 24171da177e4SLinus Torvalds } 24181da177e4SLinus Torvalds 24191da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 24201da177e4SLinus Torvalds 242163adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 242263adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 242363adc6fbSStephen Hemminger if (imn < imx) { 24241da177e4SLinus Torvalds __u32 t; 24251da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 242633d7c5e5SAkinobu Mita t = prandom_u32() % (imx - imn) + imn; 24271da177e4SLinus Torvalds else { 24281da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 24291da177e4SLinus Torvalds t++; 243063adc6fbSStephen Hemminger if (t > imx) 24311da177e4SLinus Torvalds t = imn; 243263adc6fbSStephen Hemminger 24331da177e4SLinus Torvalds } 24341da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 24351da177e4SLinus Torvalds } 24361da177e4SLinus Torvalds 2437007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24381da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24391da177e4SLinus Torvalds } else { 2440252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2441252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2442252e3346SAl Viro if (imn < imx) { 24431da177e4SLinus Torvalds __u32 t; 2444252e3346SAl Viro __be32 s; 24451da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 24461da177e4SLinus Torvalds 244770e3ba72SAkinobu Mita do { 244833d7c5e5SAkinobu Mita t = prandom_u32() % 244933d7c5e5SAkinobu Mita (imx - imn) + imn; 2450252e3346SAl Viro s = htonl(t); 245170e3ba72SAkinobu Mita } while (ipv4_is_loopback(s) || 245270e3ba72SAkinobu Mita ipv4_is_multicast(s) || 245370e3ba72SAkinobu Mita ipv4_is_lbcast(s) || 245470e3ba72SAkinobu Mita ipv4_is_zeronet(s) || 245570e3ba72SAkinobu Mita ipv4_is_local_multicast(s)); 2456252e3346SAl Viro pkt_dev->cur_daddr = s; 2457252e3346SAl Viro } else { 24581da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 24591da177e4SLinus Torvalds t++; 24601da177e4SLinus Torvalds if (t > imx) { 24611da177e4SLinus Torvalds t = imn; 24621da177e4SLinus Torvalds } 24631da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 24641da177e4SLinus Torvalds } 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds if (pkt_dev->cflows) { 2467007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2468222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2469222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2470a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2471a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 2472a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2473a553e4a6SJamal Hadi Salim #endif 24741da177e4SLinus Torvalds pkt_dev->nflows++; 24751da177e4SLinus Torvalds } 24761da177e4SLinus Torvalds } 2477222f1806SLuiz Capitulino } else { /* IPV6 * */ 2478222f1806SLuiz Capitulino 247906e30411SJoe Perches if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) { 24801da177e4SLinus Torvalds int i; 24811da177e4SLinus Torvalds 24821da177e4SLinus Torvalds /* Only random destinations yet */ 24831da177e4SLinus Torvalds 24841da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 24851da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 248633d7c5e5SAkinobu Mita (((__force __be32)prandom_u32() | 24871da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 24881da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 24891da177e4SLinus Torvalds } 24901da177e4SLinus Torvalds } 24911da177e4SLinus Torvalds } 24921da177e4SLinus Torvalds 24931da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24941da177e4SLinus Torvalds __u32 t; 24951da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 249633d7c5e5SAkinobu Mita t = prandom_u32() % 24975fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24985fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2499222f1806SLuiz Capitulino } else { 25001da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 25011da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 25021da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 25031da177e4SLinus Torvalds } 25041da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 25051da177e4SLinus Torvalds } 25061da177e4SLinus Torvalds 2507fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 250845b270f8SRobert Olsson 25091da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 25101da177e4SLinus Torvalds } 25111da177e4SLinus Torvalds 2512a553e4a6SJamal Hadi Salim 2513a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 25145537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { 2515cf93d47eSFan Du 2516cf93d47eSFan Du [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ 2517cf93d47eSFan Du }; 2518cf93d47eSFan Du 2519a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2520a553e4a6SJamal Hadi Salim { 2521a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2522a553e4a6SJamal Hadi Salim int err = 0; 25236de9ace4SFan Du struct net *net = dev_net(pkt_dev->odev); 2524a553e4a6SJamal Hadi Salim 2525a553e4a6SJamal Hadi Salim if (!x) 2526a553e4a6SJamal Hadi Salim return 0; 2527a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2528a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2529cf93d47eSFan Du if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) 2530a553e4a6SJamal Hadi Salim return 0; 2531a553e4a6SJamal Hadi Salim 2532cf93d47eSFan Du /* But when user specify an valid SPI, transformation 2533cf93d47eSFan Du * supports both transport/tunnel mode + ESP/AH type. 2534cf93d47eSFan Du */ 2535cf93d47eSFan Du if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) 2536cf93d47eSFan Du skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF; 2537cf93d47eSFan Du 2538cf93d47eSFan Du rcu_read_lock_bh(); 253913996378SHerbert Xu err = x->outer_mode->output(x, skb); 2540cf93d47eSFan Du rcu_read_unlock_bh(); 25416de9ace4SFan Du if (err) { 25426de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); 2543a553e4a6SJamal Hadi Salim goto error; 25446de9ace4SFan Du } 2545a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 25466de9ace4SFan Du if (err) { 25476de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); 2548a553e4a6SJamal Hadi Salim goto error; 25496de9ace4SFan Du } 25500af0a413SFan Du spin_lock_bh(&x->lock); 2551a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2552a553e4a6SJamal Hadi Salim x->curlft.packets++; 25530af0a413SFan Du spin_unlock_bh(&x->lock); 2554a553e4a6SJamal Hadi Salim error: 2555a553e4a6SJamal Hadi Salim return err; 2556a553e4a6SJamal Hadi Salim } 2557a553e4a6SJamal Hadi Salim 2558475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2559a553e4a6SJamal Hadi Salim { 2560a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2561a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2562d6182223SPaul Gortmaker int i; 2563d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2564a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2565a553e4a6SJamal Hadi Salim if (x) { 2566a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2567a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2568a553e4a6SJamal Hadi Salim } 2569a553e4a6SJamal Hadi Salim } 2570a553e4a6SJamal Hadi Salim } 2571a553e4a6SJamal Hadi Salim } 2572a553e4a6SJamal Hadi Salim 2573475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2574a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2575a553e4a6SJamal Hadi Salim { 2576a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) { 2577a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2578a553e4a6SJamal Hadi Salim int nhead = 0; 2579a553e4a6SJamal Hadi Salim if (x) { 2580a553e4a6SJamal Hadi Salim int ret; 2581a553e4a6SJamal Hadi Salim __u8 *eth; 25823868204dSfan.du struct iphdr *iph; 25833868204dSfan.du 2584a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2585a553e4a6SJamal Hadi Salim if (nhead > 0) { 2586a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2587a553e4a6SJamal Hadi Salim if (ret < 0) { 2588f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2589f9467eaeSJoe Perches ret); 2590b4bb4ac8SIlpo Järvinen goto err; 2591a553e4a6SJamal Hadi Salim } 2592a553e4a6SJamal Hadi Salim } 2593a553e4a6SJamal Hadi Salim 2594a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2595a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2596a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2597a553e4a6SJamal Hadi Salim if (ret) { 2598f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2599b4bb4ac8SIlpo Järvinen goto err; 2600a553e4a6SJamal Hadi Salim } 2601a553e4a6SJamal Hadi Salim /* restore ll */ 2602a553e4a6SJamal Hadi Salim eth = (__u8 *) skb_push(skb, ETH_HLEN); 2603a553e4a6SJamal Hadi Salim memcpy(eth, pkt_dev->hh, 12); 2604a553e4a6SJamal Hadi Salim *(u16 *) ð[12] = protocol; 26053868204dSfan.du 26063868204dSfan.du /* Update IPv4 header len as well as checksum value */ 26073868204dSfan.du iph = ip_hdr(skb); 26083868204dSfan.du iph->tot_len = htons(skb->len - ETH_HLEN); 26093868204dSfan.du ip_send_check(iph); 2610a553e4a6SJamal Hadi Salim } 2611a553e4a6SJamal Hadi Salim } 2612a553e4a6SJamal Hadi Salim return 1; 2613b4bb4ac8SIlpo Järvinen err: 2614b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2615b4bb4ac8SIlpo Järvinen return 0; 2616a553e4a6SJamal Hadi Salim } 2617a553e4a6SJamal Hadi Salim #endif 2618a553e4a6SJamal Hadi Salim 2619ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2620ca6549afSSteven Whitehouse { 262195c96174SEric Dumazet unsigned int i; 262263adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2623ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 262463adc6fbSStephen Hemminger 2625ca6549afSSteven Whitehouse mpls--; 2626ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2627ca6549afSSteven Whitehouse } 2628ca6549afSSteven Whitehouse 26290f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 26300f37c605SAl Viro unsigned int prio) 26310f37c605SAl Viro { 26320f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 26330f37c605SAl Viro } 26340f37c605SAl Viro 263526ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, 263626ad7879SEric Dumazet int datalen) 263726ad7879SEric Dumazet { 263826ad7879SEric Dumazet struct timeval timestamp; 263926ad7879SEric Dumazet struct pktgen_hdr *pgh; 264026ad7879SEric Dumazet 264126ad7879SEric Dumazet pgh = (struct pktgen_hdr *)skb_put(skb, sizeof(*pgh)); 264226ad7879SEric Dumazet datalen -= sizeof(*pgh); 264326ad7879SEric Dumazet 264426ad7879SEric Dumazet if (pkt_dev->nfrags <= 0) { 264505aebe2eSDaniel Turull memset(skb_put(skb, datalen), 0, datalen); 264626ad7879SEric Dumazet } else { 264726ad7879SEric Dumazet int frags = pkt_dev->nfrags; 264826ad7879SEric Dumazet int i, len; 26497d36a991Samit salecha int frag_len; 265026ad7879SEric Dumazet 265126ad7879SEric Dumazet 265226ad7879SEric Dumazet if (frags > MAX_SKB_FRAGS) 265326ad7879SEric Dumazet frags = MAX_SKB_FRAGS; 265426ad7879SEric Dumazet len = datalen - frags * PAGE_SIZE; 265526ad7879SEric Dumazet if (len > 0) { 265626ad7879SEric Dumazet memset(skb_put(skb, len), 0, len); 265726ad7879SEric Dumazet datalen = frags * PAGE_SIZE; 265826ad7879SEric Dumazet } 265926ad7879SEric Dumazet 266026ad7879SEric Dumazet i = 0; 26617d36a991Samit salecha frag_len = (datalen/frags) < PAGE_SIZE ? 26627d36a991Samit salecha (datalen/frags) : PAGE_SIZE; 266326ad7879SEric Dumazet while (datalen > 0) { 266426ad7879SEric Dumazet if (unlikely(!pkt_dev->page)) { 266526ad7879SEric Dumazet int node = numa_node_id(); 266626ad7879SEric Dumazet 266726ad7879SEric Dumazet if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE)) 266826ad7879SEric Dumazet node = pkt_dev->node; 266926ad7879SEric Dumazet pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); 267026ad7879SEric Dumazet if (!pkt_dev->page) 267126ad7879SEric Dumazet break; 267226ad7879SEric Dumazet } 2673a0bec1cdSIan Campbell get_page(pkt_dev->page); 2674ea2ab693SIan Campbell skb_frag_set_page(skb, i, pkt_dev->page); 267526ad7879SEric Dumazet skb_shinfo(skb)->frags[i].page_offset = 0; 26767d36a991Samit salecha /*last fragment, fill rest of data*/ 26777d36a991Samit salecha if (i == (frags - 1)) 26789e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], 26799e903e08SEric Dumazet (datalen < PAGE_SIZE ? datalen : PAGE_SIZE)); 26807d36a991Samit salecha else 26819e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len); 26829e903e08SEric Dumazet datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]); 26839e903e08SEric Dumazet skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 26849e903e08SEric Dumazet skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 268526ad7879SEric Dumazet i++; 268626ad7879SEric Dumazet skb_shinfo(skb)->nr_frags = i; 268726ad7879SEric Dumazet } 268826ad7879SEric Dumazet } 268926ad7879SEric Dumazet 269026ad7879SEric Dumazet /* Stamp the time, and sequence number, 269126ad7879SEric Dumazet * convert them to network byte order 269226ad7879SEric Dumazet */ 269326ad7879SEric Dumazet pgh->pgh_magic = htonl(PKTGEN_MAGIC); 269426ad7879SEric Dumazet pgh->seq_num = htonl(pkt_dev->seq_num); 269526ad7879SEric Dumazet 2696afb84b62SJesper Dangaard Brouer if (pkt_dev->flags & F_NO_TIMESTAMP) { 2697afb84b62SJesper Dangaard Brouer pgh->tv_sec = 0; 2698afb84b62SJesper Dangaard Brouer pgh->tv_usec = 0; 2699afb84b62SJesper Dangaard Brouer } else { 270026ad7879SEric Dumazet do_gettimeofday(×tamp); 270126ad7879SEric Dumazet pgh->tv_sec = htonl(timestamp.tv_sec); 270226ad7879SEric Dumazet pgh->tv_usec = htonl(timestamp.tv_usec); 270326ad7879SEric Dumazet } 2704afb84b62SJesper Dangaard Brouer } 270526ad7879SEric Dumazet 27067a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev, 27077a6e288dSDaniel Borkmann struct pktgen_dev *pkt_dev, 27087a6e288dSDaniel Borkmann unsigned int extralen) 27097a6e288dSDaniel Borkmann { 27107a6e288dSDaniel Borkmann struct sk_buff *skb = NULL; 27117a6e288dSDaniel Borkmann unsigned int size = pkt_dev->cur_pkt_size + 64 + extralen + 27127a6e288dSDaniel Borkmann pkt_dev->pkt_overhead; 27137a6e288dSDaniel Borkmann 27147a6e288dSDaniel Borkmann if (pkt_dev->flags & F_NODE) { 27157a6e288dSDaniel Borkmann int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id(); 27167a6e288dSDaniel Borkmann 27177a6e288dSDaniel Borkmann skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node); 27187a6e288dSDaniel Borkmann if (likely(skb)) { 27197a6e288dSDaniel Borkmann skb_reserve(skb, NET_SKB_PAD); 27207a6e288dSDaniel Borkmann skb->dev = dev; 27217a6e288dSDaniel Borkmann } 27227a6e288dSDaniel Borkmann } else { 27237a6e288dSDaniel Borkmann skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT); 27247a6e288dSDaniel Borkmann } 27257a6e288dSDaniel Borkmann 27267a6e288dSDaniel Borkmann return skb; 27277a6e288dSDaniel Borkmann } 27287a6e288dSDaniel Borkmann 27291da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 27301da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 27311da177e4SLinus Torvalds { 27321da177e4SLinus Torvalds struct sk_buff *skb = NULL; 27331da177e4SLinus Torvalds __u8 *eth; 27341da177e4SLinus Torvalds struct udphdr *udph; 27351da177e4SLinus Torvalds int datalen, iplen; 27361da177e4SLinus Torvalds struct iphdr *iph; 2737d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2738ca6549afSSteven Whitehouse __be32 *mpls; 273934954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 274034954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 274134954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 274234954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2743fd2ea0a7SDavid S. Miller u16 queue_map; 2744ca6549afSSteven Whitehouse 2745ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2746d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 27471da177e4SLinus Torvalds 274834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2749d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 275034954ddcSFrancesco Fondelli 275164053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 275264053beeSRobert Olsson * fields. 275364053beeSRobert Olsson */ 275464053beeSRobert Olsson mod_cur_headers(pkt_dev); 2755eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 275664053beeSRobert Olsson 27577ac5459eSDavid S. Miller datalen = (odev->hard_header_len + 16) & ~0xf; 2758e99b99b4SRobert Olsson 27597a6e288dSDaniel Borkmann skb = pktgen_alloc_skb(odev, pkt_dev, datalen); 27601da177e4SLinus Torvalds if (!skb) { 27611da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 27621da177e4SLinus Torvalds return NULL; 27631da177e4SLinus Torvalds } 27641da177e4SLinus Torvalds 27657a6e288dSDaniel Borkmann prefetchw(skb->data); 27667ac5459eSDavid S. Miller skb_reserve(skb, datalen); 27671da177e4SLinus Torvalds 27681da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 27691da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2770ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2771ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2772ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 277334954ddcSFrancesco Fondelli 277434954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 277534954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 277634954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 27770f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 27780f37c605SAl Viro pkt_dev->svlan_cfi, 27790f37c605SAl Viro pkt_dev->svlan_p); 278034954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2781d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 278234954ddcSFrancesco Fondelli } 278334954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 27840f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 27850f37c605SAl Viro pkt_dev->vlan_cfi, 27860f37c605SAl Viro pkt_dev->vlan_p); 278734954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2788d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 278934954ddcSFrancesco Fondelli } 279034954ddcSFrancesco Fondelli 2791525cebedSThomas Graf skb_set_mac_header(skb, 0); 2792525cebedSThomas Graf skb_set_network_header(skb, skb->len); 2793525cebedSThomas Graf iph = (struct iphdr *) skb_put(skb, sizeof(struct iphdr)); 2794525cebedSThomas Graf 2795525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 2796525cebedSThomas Graf udph = (struct udphdr *) skb_put(skb, sizeof(struct udphdr)); 2797fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 27989e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 27999e50e3acSJohn Fastabend 28001da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2801252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 28021da177e4SLinus Torvalds 2803ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2804ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 280516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 28066af773e7SNishank Trivedi if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) 28071da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 28081da177e4SLinus Torvalds 28091da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 28101da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 28111da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 2812c26bf4a5SThomas Graf udph->check = 0; 28131da177e4SLinus Torvalds 28141da177e4SLinus Torvalds iph->ihl = 5; 28151da177e4SLinus Torvalds iph->version = 4; 28161da177e4SLinus Torvalds iph->ttl = 32; 28171ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 28181da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 28191da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 28201da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 282166ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 282266ed1e5eSEric Dumazet pkt_dev->ip_id++; 28231da177e4SLinus Torvalds iph->frag_off = 0; 28241da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 28251da177e4SLinus Torvalds iph->tot_len = htons(iplen); 282603c633e7SThomas Graf ip_send_check(iph); 2827ca6549afSSteven Whitehouse skb->protocol = protocol; 28281da177e4SLinus Torvalds skb->dev = odev; 28291da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 2830c26bf4a5SThomas Graf 2831c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 2832c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 2833c26bf4a5SThomas Graf } else if (odev->features & NETIF_F_V4_CSUM) { 2834c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 2835c26bf4a5SThomas Graf skb->csum = 0; 2836c26bf4a5SThomas Graf udp4_hwcsum(skb, udph->source, udph->dest); 2837c26bf4a5SThomas Graf } else { 2838c26bf4a5SThomas Graf __wsum csum = udp_csum(skb); 2839c26bf4a5SThomas Graf 2840c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 2841c26bf4a5SThomas Graf udph->check = csum_tcpudp_magic(udph->source, udph->dest, 2842c26bf4a5SThomas Graf datalen + 8, IPPROTO_UDP, csum); 2843c26bf4a5SThomas Graf 2844c26bf4a5SThomas Graf if (udph->check == 0) 2845c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 2846c26bf4a5SThomas Graf } 2847c26bf4a5SThomas Graf 284826ad7879SEric Dumazet pktgen_finalize_skb(pkt_dev, skb, datalen); 28491da177e4SLinus Torvalds 2850a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2851a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2852a553e4a6SJamal Hadi Salim return NULL; 2853a553e4a6SJamal Hadi Salim #endif 2854a553e4a6SJamal Hadi Salim 28551da177e4SLinus Torvalds return skb; 28561da177e4SLinus Torvalds } 28571da177e4SLinus Torvalds 28581da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 28591da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 28601da177e4SLinus Torvalds { 28611da177e4SLinus Torvalds struct sk_buff *skb = NULL; 28621da177e4SLinus Torvalds __u8 *eth; 28631da177e4SLinus Torvalds struct udphdr *udph; 2864c26bf4a5SThomas Graf int datalen, udplen; 28651da177e4SLinus Torvalds struct ipv6hdr *iph; 2866d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2867ca6549afSSteven Whitehouse __be32 *mpls; 286834954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 286934954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 287034954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 287134954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2872fd2ea0a7SDavid S. Miller u16 queue_map; 2873ca6549afSSteven Whitehouse 2874ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2875d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 28761da177e4SLinus Torvalds 287734954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2878d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 287934954ddcSFrancesco Fondelli 288064053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 288164053beeSRobert Olsson * fields. 288264053beeSRobert Olsson */ 288364053beeSRobert Olsson mod_cur_headers(pkt_dev); 2884eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 288564053beeSRobert Olsson 28867a6e288dSDaniel Borkmann skb = pktgen_alloc_skb(odev, pkt_dev, 16); 28871da177e4SLinus Torvalds if (!skb) { 28881da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 28891da177e4SLinus Torvalds return NULL; 28901da177e4SLinus Torvalds } 28911da177e4SLinus Torvalds 28927a6e288dSDaniel Borkmann prefetchw(skb->data); 28931da177e4SLinus Torvalds skb_reserve(skb, 16); 28941da177e4SLinus Torvalds 28951da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 28961da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2897ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2898ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2899ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 290034954ddcSFrancesco Fondelli 290134954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 290234954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 290334954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 29040f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 29050f37c605SAl Viro pkt_dev->svlan_cfi, 29060f37c605SAl Viro pkt_dev->svlan_p); 290734954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2908d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 290934954ddcSFrancesco Fondelli } 291034954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 29110f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 29120f37c605SAl Viro pkt_dev->vlan_cfi, 29130f37c605SAl Viro pkt_dev->vlan_p); 291434954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2915d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 291634954ddcSFrancesco Fondelli } 291734954ddcSFrancesco Fondelli 2918525cebedSThomas Graf skb_set_mac_header(skb, 0); 2919525cebedSThomas Graf skb_set_network_header(skb, skb->len); 2920525cebedSThomas Graf iph = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr)); 2921525cebedSThomas Graf 2922525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 2923525cebedSThomas Graf udph = (struct udphdr *) skb_put(skb, sizeof(struct udphdr)); 2924fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 29259e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 29261da177e4SLinus Torvalds 29271da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2928252e3346SAl Viro *(__be16 *) ð[12] = protocol; 29291da177e4SLinus Torvalds 2930ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2931ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 2932ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 293316dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 29341da177e4SLinus Torvalds 29355aa8b572SAmerigo Wang if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { 29361da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 2937e87cc472SJoe Perches net_info_ratelimited("increased datalen to %d\n", datalen); 29381da177e4SLinus Torvalds } 29391da177e4SLinus Torvalds 2940c26bf4a5SThomas Graf udplen = datalen + sizeof(struct udphdr); 29411da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 29421da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 2943c26bf4a5SThomas Graf udph->len = htons(udplen); 2944c26bf4a5SThomas Graf udph->check = 0; 29451da177e4SLinus Torvalds 2946d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 29471da177e4SLinus Torvalds 29481ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 29491ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 2950252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 29511ca7768cSFrancesco Fondelli } 29521ca7768cSFrancesco Fondelli 29531da177e4SLinus Torvalds iph->hop_limit = 32; 29541da177e4SLinus Torvalds 2955c26bf4a5SThomas Graf iph->payload_len = htons(udplen); 29561da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 29571da177e4SLinus Torvalds 29584e3fd7a0SAlexey Dobriyan iph->daddr = pkt_dev->cur_in6_daddr; 29594e3fd7a0SAlexey Dobriyan iph->saddr = pkt_dev->cur_in6_saddr; 29601da177e4SLinus Torvalds 2961ca6549afSSteven Whitehouse skb->protocol = protocol; 29621da177e4SLinus Torvalds skb->dev = odev; 29631da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 29641da177e4SLinus Torvalds 2965c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 2966c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 2967c26bf4a5SThomas Graf } else if (odev->features & NETIF_F_V6_CSUM) { 2968c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 2969c26bf4a5SThomas Graf skb->csum_start = skb_transport_header(skb) - skb->head; 2970c26bf4a5SThomas Graf skb->csum_offset = offsetof(struct udphdr, check); 2971c26bf4a5SThomas Graf udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0); 2972c26bf4a5SThomas Graf } else { 2973c26bf4a5SThomas Graf __wsum csum = udp_csum(skb); 2974c26bf4a5SThomas Graf 2975c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 2976c26bf4a5SThomas Graf udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum); 2977c26bf4a5SThomas Graf 2978c26bf4a5SThomas Graf if (udph->check == 0) 2979c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 2980c26bf4a5SThomas Graf } 2981c26bf4a5SThomas Graf 298226ad7879SEric Dumazet pktgen_finalize_skb(pkt_dev, skb, datalen); 29831da177e4SLinus Torvalds 29841da177e4SLinus Torvalds return skb; 29851da177e4SLinus Torvalds } 29861da177e4SLinus Torvalds 2987475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 29881da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29891da177e4SLinus Torvalds { 29901da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 29911da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 29921da177e4SLinus Torvalds else 29931da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 29941da177e4SLinus Torvalds } 29951da177e4SLinus Torvalds 29961da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 29971da177e4SLinus Torvalds { 29981da177e4SLinus Torvalds pkt_dev->seq_num = 1; 29991da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 30001da177e4SLinus Torvalds pkt_dev->sofar = 0; 30011da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 30021da177e4SLinus Torvalds pkt_dev->errors = 0; 30031da177e4SLinus Torvalds } 30041da177e4SLinus Torvalds 30051da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 30061da177e4SLinus Torvalds 30071da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 30081da177e4SLinus Torvalds { 3009c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 30101da177e4SLinus Torvalds int started = 0; 30111da177e4SLinus Torvalds 3012f9467eaeSJoe Perches func_enter(); 30131da177e4SLinus Torvalds 30148788370aSJesper Dangaard Brouer rcu_read_lock(); 30158788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 30161da177e4SLinus Torvalds 30171da177e4SLinus Torvalds /* 30181da177e4SLinus Torvalds * setup odev and create initial packet. 30191da177e4SLinus Torvalds */ 30201da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 30211da177e4SLinus Torvalds 30221da177e4SLinus Torvalds if (pkt_dev->odev) { 30231da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 30241da177e4SLinus Torvalds pkt_dev->skb = NULL; 3025398f382cSDaniel Borkmann pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); 3026fd29cf72SStephen Hemminger 302716dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 30308788370aSJesper Dangaard Brouer pkt_dev->running = 1; /* Cranke yeself! */ 30311da177e4SLinus Torvalds started++; 3032222f1806SLuiz Capitulino } else 30331da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 30341da177e4SLinus Torvalds } 30358788370aSJesper Dangaard Brouer rcu_read_unlock(); 3036222f1806SLuiz Capitulino if (started) 3037222f1806SLuiz Capitulino t->control &= ~(T_STOP); 30381da177e4SLinus Torvalds } 30391da177e4SLinus Torvalds 30404e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn) 30411da177e4SLinus Torvalds { 3042cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 30431da177e4SLinus Torvalds 3044f9467eaeSJoe Perches func_enter(); 30451da177e4SLinus Torvalds 30466146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3047cdcdbe0bSLuiz Capitulino 30484e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 304995ed63f7SArthur Kepner t->control |= T_STOP; 3050cdcdbe0bSLuiz Capitulino 30516146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 30521da177e4SLinus Torvalds } 30531da177e4SLinus Torvalds 3054648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 30551da177e4SLinus Torvalds { 3056648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 30571da177e4SLinus Torvalds 30588788370aSJesper Dangaard Brouer rcu_read_lock(); 30598788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 30608788370aSJesper Dangaard Brouer if (pkt_dev->running) { 30618788370aSJesper Dangaard Brouer rcu_read_unlock(); 3062648fda74SStephen Hemminger return 1; 30638788370aSJesper Dangaard Brouer } 30648788370aSJesper Dangaard Brouer rcu_read_unlock(); 3065648fda74SStephen Hemminger return 0; 30661da177e4SLinus Torvalds } 30671da177e4SLinus Torvalds 30681da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 30691da177e4SLinus Torvalds { 30701da177e4SLinus Torvalds while (thread_is_running(t)) { 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds msleep_interruptible(100); 30731da177e4SLinus Torvalds 30741da177e4SLinus Torvalds if (signal_pending(current)) 30751da177e4SLinus Torvalds goto signal; 30761da177e4SLinus Torvalds } 30771da177e4SLinus Torvalds return 1; 30781da177e4SLinus Torvalds signal: 30791da177e4SLinus Torvalds return 0; 30801da177e4SLinus Torvalds } 30811da177e4SLinus Torvalds 30824e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn) 30831da177e4SLinus Torvalds { 3084cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 30851da177e4SLinus Torvalds int sig = 1; 30861da177e4SLinus Torvalds 30876146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3088cdcdbe0bSLuiz Capitulino 30894e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 30901da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3091222f1806SLuiz Capitulino if (sig == 0) 3092222f1806SLuiz Capitulino break; 30931da177e4SLinus Torvalds } 3094cdcdbe0bSLuiz Capitulino 3095cdcdbe0bSLuiz Capitulino if (sig == 0) 30964e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 30971da177e4SLinus Torvalds t->control |= (T_STOP); 3098cdcdbe0bSLuiz Capitulino 30996146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 31001da177e4SLinus Torvalds return sig; 31011da177e4SLinus Torvalds } 31021da177e4SLinus Torvalds 31034e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn) 31041da177e4SLinus Torvalds { 3105cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31061da177e4SLinus Torvalds 3107f9467eaeSJoe Perches func_enter(); 31081da177e4SLinus Torvalds 31096146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 31101da177e4SLinus Torvalds 31114e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 31121da177e4SLinus Torvalds t->control |= (T_RUN); 3113cdcdbe0bSLuiz Capitulino 31146146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 31151da177e4SLinus Torvalds 311663adc6fbSStephen Hemminger /* Propagate thread->control */ 311763adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 31181da177e4SLinus Torvalds 31194e58a027SCong Wang pktgen_wait_all_threads_run(pn); 31201da177e4SLinus Torvalds } 31211da177e4SLinus Torvalds 31224e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn) 3123eb37b41cSJesse Brandeburg { 3124eb37b41cSJesse Brandeburg struct pktgen_thread *t; 3125eb37b41cSJesse Brandeburg 3126f9467eaeSJoe Perches func_enter(); 3127eb37b41cSJesse Brandeburg 3128eb37b41cSJesse Brandeburg mutex_lock(&pktgen_thread_lock); 3129eb37b41cSJesse Brandeburg 31304e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 3131eb37b41cSJesse Brandeburg t->control |= (T_REMDEVALL); 3132eb37b41cSJesse Brandeburg 3133eb37b41cSJesse Brandeburg mutex_unlock(&pktgen_thread_lock); 3134eb37b41cSJesse Brandeburg 313563adc6fbSStephen Hemminger /* Propagate thread->control */ 313663adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3137eb37b41cSJesse Brandeburg 31384e58a027SCong Wang pktgen_wait_all_threads_run(pn); 3139eb37b41cSJesse Brandeburg } 3140eb37b41cSJesse Brandeburg 31411da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 31421da177e4SLinus Torvalds { 3143fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 31441da177e4SLinus Torvalds char *p = pkt_dev->result; 3145fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3146fd29cf72SStephen Hemminger pkt_dev->started_at); 3147fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 31481da177e4SLinus Torvalds 314903a14ab1SDaniel Turull p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 3150fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3151fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3152fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 31531da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 31541da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 31551da177e4SLinus Torvalds 3156fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3157fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 31581da177e4SLinus Torvalds 31591da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 31601da177e4SLinus Torvalds 31611da177e4SLinus Torvalds mbps = bps; 31621da177e4SLinus Torvalds do_div(mbps, 1000000); 31631da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 31641da177e4SLinus Torvalds (unsigned long long)pps, 31651da177e4SLinus Torvalds (unsigned long long)mbps, 31661da177e4SLinus Torvalds (unsigned long long)bps, 31671da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 31681da177e4SLinus Torvalds } 31691da177e4SLinus Torvalds 31701da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 31711da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 31721da177e4SLinus Torvalds { 3173222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 31741da177e4SLinus Torvalds 31751da177e4SLinus Torvalds if (!pkt_dev->running) { 3176*294a0b7fSJoe Perches pr_warn("interface: %s is already stopped\n", 3177f9467eaeSJoe Perches pkt_dev->odevname); 31781da177e4SLinus Torvalds return -EINVAL; 31791da177e4SLinus Torvalds } 31801da177e4SLinus Torvalds 31818788370aSJesper Dangaard Brouer pkt_dev->running = 0; 31823bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 31833bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3184398f382cSDaniel Borkmann pkt_dev->stopped_at = ktime_get(); 31851da177e4SLinus Torvalds 318695ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 31871da177e4SLinus Torvalds 31881da177e4SLinus Torvalds return 0; 31891da177e4SLinus Torvalds } 31901da177e4SLinus Torvalds 31911da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 31921da177e4SLinus Torvalds { 3193c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 31941da177e4SLinus Torvalds 31958788370aSJesper Dangaard Brouer rcu_read_lock(); 31968788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3197c26a8016SLuiz Capitulino if (!pkt_dev->running) 3198222f1806SLuiz Capitulino continue; 3199222f1806SLuiz Capitulino if (best == NULL) 3200c26a8016SLuiz Capitulino best = pkt_dev; 3201398f382cSDaniel Borkmann else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) 3202c26a8016SLuiz Capitulino best = pkt_dev; 32031da177e4SLinus Torvalds } 32048788370aSJesper Dangaard Brouer rcu_read_unlock(); 32058788370aSJesper Dangaard Brouer 32061da177e4SLinus Torvalds return best; 32071da177e4SLinus Torvalds } 32081da177e4SLinus Torvalds 3209222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3210222f1806SLuiz Capitulino { 3211c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 32121da177e4SLinus Torvalds 3213f9467eaeSJoe Perches func_enter(); 32141da177e4SLinus Torvalds 32158788370aSJesper Dangaard Brouer rcu_read_lock(); 32161da177e4SLinus Torvalds 32178788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3218c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 321995ed63f7SArthur Kepner } 322095ed63f7SArthur Kepner 32218788370aSJesper Dangaard Brouer rcu_read_unlock(); 322295ed63f7SArthur Kepner } 322395ed63f7SArthur Kepner 322495ed63f7SArthur Kepner /* 322595ed63f7SArthur Kepner * one of our devices needs to be removed - find it 322695ed63f7SArthur Kepner * and remove it 322795ed63f7SArthur Kepner */ 322895ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 322995ed63f7SArthur Kepner { 3230c26a8016SLuiz Capitulino struct list_head *q, *n; 3231c26a8016SLuiz Capitulino struct pktgen_dev *cur; 323295ed63f7SArthur Kepner 3233f9467eaeSJoe Perches func_enter(); 323495ed63f7SArthur Kepner 3235c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3236c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 323795ed63f7SArthur Kepner 3238222f1806SLuiz Capitulino if (!cur->removal_mark) 3239222f1806SLuiz Capitulino continue; 324095ed63f7SArthur Kepner 324195ed63f7SArthur Kepner kfree_skb(cur->skb); 324295ed63f7SArthur Kepner cur->skb = NULL; 324395ed63f7SArthur Kepner 324495ed63f7SArthur Kepner pktgen_remove_device(t, cur); 324595ed63f7SArthur Kepner 324695ed63f7SArthur Kepner break; 324795ed63f7SArthur Kepner } 32481da177e4SLinus Torvalds } 32491da177e4SLinus Torvalds 32501da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 32511da177e4SLinus Torvalds { 3252c26a8016SLuiz Capitulino struct list_head *q, *n; 3253c26a8016SLuiz Capitulino struct pktgen_dev *cur; 32541da177e4SLinus Torvalds 3255f9467eaeSJoe Perches func_enter(); 3256f9467eaeSJoe Perches 32571da177e4SLinus Torvalds /* Remove all devices, free mem */ 32581da177e4SLinus Torvalds 3259c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3260c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 326195ed63f7SArthur Kepner 326295ed63f7SArthur Kepner kfree_skb(cur->skb); 326395ed63f7SArthur Kepner cur->skb = NULL; 326495ed63f7SArthur Kepner 32651da177e4SLinus Torvalds pktgen_remove_device(t, cur); 32661da177e4SLinus Torvalds } 32671da177e4SLinus Torvalds } 32681da177e4SLinus Torvalds 32691da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 32701da177e4SLinus Torvalds { 32711da177e4SLinus Torvalds /* Remove from the thread list */ 32724e58a027SCong Wang remove_proc_entry(t->tsk->comm, t->net->proc_dir); 32731da177e4SLinus Torvalds } 32741da177e4SLinus Torvalds 3275ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 32763791decbSStephen Hemminger { 3277398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 32783791decbSStephen Hemminger schedule(); 3279398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 32803791decbSStephen Hemminger } 32813791decbSStephen Hemminger 3282ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3283ef87979cSStephen Hemminger { 3284398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 3285ef87979cSStephen Hemminger 3286ef87979cSStephen Hemminger while (atomic_read(&(pkt_dev->skb->users)) != 1) { 3287ef87979cSStephen Hemminger if (signal_pending(current)) 3288ef87979cSStephen Hemminger break; 3289ef87979cSStephen Hemminger 3290ef87979cSStephen Hemminger if (need_resched()) 3291ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3292ef87979cSStephen Hemminger else 3293ef87979cSStephen Hemminger cpu_relax(); 3294ef87979cSStephen Hemminger } 3295398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 3296ef87979cSStephen Hemminger } 3297fd29cf72SStephen Hemminger 3298475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 32991da177e4SLinus Torvalds { 330000829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 3301fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 33021da177e4SLinus Torvalds int ret; 33031da177e4SLinus Torvalds 3304ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3305ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 33061da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 33073791decbSStephen Hemminger return; 33081da177e4SLinus Torvalds } 33091da177e4SLinus Torvalds 3310ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3311ef87979cSStephen Hemminger * "never transmit" 3312ef87979cSStephen Hemminger */ 3313ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3314398f382cSDaniel Borkmann pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX); 3315ef87979cSStephen Hemminger return; 3316ef87979cSStephen Hemminger } 3317ef87979cSStephen Hemminger 3318ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 33197d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 33207d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 33211da177e4SLinus Torvalds /* build a new pkt */ 33221da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 33231da177e4SLinus Torvalds 33241da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 33251da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3326f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 33271da177e4SLinus Torvalds schedule(); 33281da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 33293791decbSStephen Hemminger return; 33301da177e4SLinus Torvalds } 3331baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 33321da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 33331da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 33341da177e4SLinus Torvalds } 33351da177e4SLinus Torvalds 3336ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3337ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3338ef87979cSStephen Hemminger 333910c51b56SDaniel Borkmann txq = skb_get_tx_queue(odev, pkt_dev->skb); 3340fd2ea0a7SDavid S. Miller 33410f2eea4bSDaniel Borkmann local_bh_disable(); 33420f2eea4bSDaniel Borkmann 33430f2eea4bSDaniel Borkmann HARD_TX_LOCK(odev, txq, smp_processor_id()); 33445b8db2f5SStephen Hemminger 33456f25cd47SDaniel Borkmann if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) { 3346ef87979cSStephen Hemminger ret = NETDEV_TX_BUSY; 33470835acfeSEric Dumazet pkt_dev->last_ok = 0; 33480835acfeSEric Dumazet goto unlock; 33490835acfeSEric Dumazet } 33500835acfeSEric Dumazet atomic_inc(&(pkt_dev->skb->users)); 3351fa2dbdc2SDavid S. Miller ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false); 3352ef87979cSStephen Hemminger 33535b8db2f5SStephen Hemminger switch (ret) { 33545b8db2f5SStephen Hemminger case NETDEV_TX_OK: 33551da177e4SLinus Torvalds pkt_dev->last_ok = 1; 33561da177e4SLinus Torvalds pkt_dev->sofar++; 33571da177e4SLinus Torvalds pkt_dev->seq_num++; 3358baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 33595b8db2f5SStephen Hemminger break; 3360f466dba1SJohn Fastabend case NET_XMIT_DROP: 3361f466dba1SJohn Fastabend case NET_XMIT_CN: 3362f466dba1SJohn Fastabend case NET_XMIT_POLICED: 3363f466dba1SJohn Fastabend /* skb has been consumed */ 3364f466dba1SJohn Fastabend pkt_dev->errors++; 3365f466dba1SJohn Fastabend break; 33665b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 3367e87cc472SJoe Perches net_info_ratelimited("%s xmit error: %d\n", 3368e87cc472SJoe Perches pkt_dev->odevname, ret); 33691da177e4SLinus Torvalds pkt_dev->errors++; 33705b8db2f5SStephen Hemminger /* fallthru */ 3371ef87979cSStephen Hemminger case NETDEV_TX_LOCKED: 33725b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 33735b8db2f5SStephen Hemminger /* Retry it next time */ 33745b8db2f5SStephen Hemminger atomic_dec(&(pkt_dev->skb->users)); 33751da177e4SLinus Torvalds pkt_dev->last_ok = 0; 33761da177e4SLinus Torvalds } 33770835acfeSEric Dumazet unlock: 33780f2eea4bSDaniel Borkmann HARD_TX_UNLOCK(odev, txq); 33790f2eea4bSDaniel Borkmann 33800f2eea4bSDaniel Borkmann local_bh_enable(); 33811da177e4SLinus Torvalds 33821da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 33831da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3384ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 33851da177e4SLinus Torvalds 33861da177e4SLinus Torvalds /* Done with this */ 33871da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 33881da177e4SLinus Torvalds } 33891da177e4SLinus Torvalds } 33901da177e4SLinus Torvalds 33911da177e4SLinus Torvalds /* 33921da177e4SLinus Torvalds * Main loop of the thread goes here 33931da177e4SLinus Torvalds */ 33941da177e4SLinus Torvalds 3395ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 33961da177e4SLinus Torvalds { 33971da177e4SLinus Torvalds DEFINE_WAIT(wait); 3398ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 33991da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 34001da177e4SLinus Torvalds int cpu = t->cpu; 34011da177e4SLinus Torvalds 3402ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 34031da177e4SLinus Torvalds 34041da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3405d3ede327SDenis V. Lunev complete(&t->start_done); 34061da177e4SLinus Torvalds 3407f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 34081da177e4SLinus Torvalds 340983144186SRafael J. Wysocki set_freezable(); 341083144186SRafael J. Wysocki 3411baac167bSJesper Dangaard Brouer __set_current_state(TASK_RUNNING); 3412baac167bSJesper Dangaard Brouer 3413ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3414ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3415ee74baa7SDavid S. Miller 3416ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 34174e58a027SCong Wang if (t->net->pktgen_exiting) 3418551eaff1SEric Dumazet break; 3419ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3420ef87979cSStephen Hemminger t->control != 0, 3421ef87979cSStephen Hemminger HZ/10); 34221b3f720bSRafael J. Wysocki try_to_freeze(); 3423ef87979cSStephen Hemminger continue; 3424ee74baa7SDavid S. Miller } 34251da177e4SLinus Torvalds 3426ef87979cSStephen Hemminger if (likely(pkt_dev)) { 34271da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 34281da177e4SLinus Torvalds 3429ef87979cSStephen Hemminger if (need_resched()) 3430ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3431ef87979cSStephen Hemminger else 3432ef87979cSStephen Hemminger cpu_relax(); 3433ef87979cSStephen Hemminger } 3434ef87979cSStephen Hemminger 34351da177e4SLinus Torvalds if (t->control & T_STOP) { 34361da177e4SLinus Torvalds pktgen_stop(t); 34371da177e4SLinus Torvalds t->control &= ~(T_STOP); 34381da177e4SLinus Torvalds } 34391da177e4SLinus Torvalds 34401da177e4SLinus Torvalds if (t->control & T_RUN) { 34411da177e4SLinus Torvalds pktgen_run(t); 34421da177e4SLinus Torvalds t->control &= ~(T_RUN); 34431da177e4SLinus Torvalds } 34441da177e4SLinus Torvalds 344595ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 34461da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 344795ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 344895ed63f7SArthur Kepner } 344995ed63f7SArthur Kepner 345095ed63f7SArthur Kepner if (t->control & T_REMDEV) { 345195ed63f7SArthur Kepner pktgen_rem_one_if(t); 34521da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 34531da177e4SLinus Torvalds } 34541da177e4SLinus Torvalds 345509fe3ef4SAndrew Morton try_to_freeze(); 34561da177e4SLinus Torvalds } 3457baac167bSJesper Dangaard Brouer set_current_state(TASK_INTERRUPTIBLE); 34581da177e4SLinus Torvalds 3459f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 34601da177e4SLinus Torvalds pktgen_stop(t); 34611da177e4SLinus Torvalds 3462f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 34631da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 34641da177e4SLinus Torvalds 3465f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 34661da177e4SLinus Torvalds pktgen_rem_thread(t); 3467cdcdbe0bSLuiz Capitulino 3468551eaff1SEric Dumazet /* Wait for kthread_stop */ 3469551eaff1SEric Dumazet while (!kthread_should_stop()) { 3470551eaff1SEric Dumazet set_current_state(TASK_INTERRUPTIBLE); 3471551eaff1SEric Dumazet schedule(); 3472551eaff1SEric Dumazet } 3473551eaff1SEric Dumazet __set_current_state(TASK_RUNNING); 3474551eaff1SEric Dumazet 3475ee74baa7SDavid S. Miller return 0; 34761da177e4SLinus Torvalds } 34771da177e4SLinus Torvalds 3478222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 34793e984840SEric Dumazet const char *ifname, bool exact) 34801da177e4SLinus Torvalds { 3481c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 34823e984840SEric Dumazet size_t len = strlen(ifname); 34831da177e4SLinus Torvalds 34848788370aSJesper Dangaard Brouer rcu_read_lock(); 34858788370aSJesper Dangaard Brouer list_for_each_entry_rcu(p, &t->if_list, list) 34863e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 34873e984840SEric Dumazet if (p->odevname[len]) { 34883e984840SEric Dumazet if (exact || p->odevname[len] != '@') 34893e984840SEric Dumazet continue; 34903e984840SEric Dumazet } 3491c26a8016SLuiz Capitulino pkt_dev = p; 34921da177e4SLinus Torvalds break; 34931da177e4SLinus Torvalds } 34941da177e4SLinus Torvalds 34958788370aSJesper Dangaard Brouer rcu_read_unlock(); 3496f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 34971da177e4SLinus Torvalds return pkt_dev; 34981da177e4SLinus Torvalds } 34991da177e4SLinus Torvalds 35001da177e4SLinus Torvalds /* 35011da177e4SLinus Torvalds * Adds a dev at front of if_list. 35021da177e4SLinus Torvalds */ 35031da177e4SLinus Torvalds 3504222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3505222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 35061da177e4SLinus Torvalds { 35071da177e4SLinus Torvalds int rv = 0; 35081da177e4SLinus Torvalds 35098788370aSJesper Dangaard Brouer /* This function cannot be called concurrently, as its called 35108788370aSJesper Dangaard Brouer * under pktgen_thread_lock mutex, but it can run from 35118788370aSJesper Dangaard Brouer * userspace on another CPU than the kthread. The if_lock() 35128788370aSJesper Dangaard Brouer * is used here to sync with concurrent instances of 35138788370aSJesper Dangaard Brouer * _rem_dev_from_if_list() invoked via kthread, which is also 35148788370aSJesper Dangaard Brouer * updating the if_list */ 35151da177e4SLinus Torvalds if_lock(t); 35161da177e4SLinus Torvalds 35171da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3518f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 35191da177e4SLinus Torvalds rv = -EBUSY; 35201da177e4SLinus Torvalds goto out; 35211da177e4SLinus Torvalds } 3522c26a8016SLuiz Capitulino 35231da177e4SLinus Torvalds pkt_dev->running = 0; 35248788370aSJesper Dangaard Brouer pkt_dev->pg_thread = t; 35258788370aSJesper Dangaard Brouer list_add_rcu(&pkt_dev->list, &t->if_list); 35261da177e4SLinus Torvalds 35271da177e4SLinus Torvalds out: 35281da177e4SLinus Torvalds if_unlock(t); 35291da177e4SLinus Torvalds return rv; 35301da177e4SLinus Torvalds } 35311da177e4SLinus Torvalds 35321da177e4SLinus Torvalds /* Called under thread lock */ 35331da177e4SLinus Torvalds 35341da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 35351da177e4SLinus Torvalds { 35361da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 353739df232fSStephen Hemminger int err; 35383291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 35391da177e4SLinus Torvalds 35401da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 35411da177e4SLinus Torvalds 35424e58a027SCong Wang pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND); 3543d50a6b56SStephen Hemminger if (pkt_dev) { 3544f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3545d50a6b56SStephen Hemminger return -EBUSY; 3546d50a6b56SStephen Hemminger } 35471da177e4SLinus Torvalds 35483291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 35491da177e4SLinus Torvalds if (!pkt_dev) 35501da177e4SLinus Torvalds return -ENOMEM; 35511da177e4SLinus Torvalds 3552593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 355368d5ac2eSWANG Cong pkt_dev->flows = vzalloc_node(MAX_CFLOWS * sizeof(struct flow_state), 35543291b9dbSEric Dumazet node); 35551da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 35561da177e4SLinus Torvalds kfree(pkt_dev); 35571da177e4SLinus Torvalds return -ENOMEM; 35581da177e4SLinus Torvalds } 35591da177e4SLinus Torvalds 356095ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 35611da177e4SLinus Torvalds pkt_dev->nfrags = 0; 3562fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 35631da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 35641da177e4SLinus Torvalds pkt_dev->sofar = 0; 35651da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 35661da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 35671da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 35681da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 356934954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 357034954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 357134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 357234954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 357334954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 357434954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 3575e99b99b4SRobert Olsson pkt_dev->node = -1; 357634954ddcSFrancesco Fondelli 35774e58a027SCong Wang err = pktgen_setup_dev(t->net, pkt_dev, ifname); 357839df232fSStephen Hemminger if (err) 357939df232fSStephen Hemminger goto out1; 3580d8873315SNeil Horman if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) 3581d8873315SNeil Horman pkt_dev->clone_skb = pg_clone_skb_d; 35821da177e4SLinus Torvalds 35834e58a027SCong Wang pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir, 35845efdccbcSDenis V. Lunev &pktgen_if_fops, pkt_dev); 358539df232fSStephen Hemminger if (!pkt_dev->entry) { 3586f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3587d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 358839df232fSStephen Hemminger err = -EINVAL; 358939df232fSStephen Hemminger goto out2; 359039df232fSStephen Hemminger } 3591a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3592a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3593a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3594cf93d47eSFan Du 3595cf93d47eSFan Du /* xfrm tunnel mode needs additional dst to extract outter 3596cf93d47eSFan Du * ip header protocol/ttl/id field, here creat a phony one. 3597cf93d47eSFan Du * instead of looking for a valid rt, which definitely hurting 3598cf93d47eSFan Du * performance under such circumstance. 3599cf93d47eSFan Du */ 3600cf93d47eSFan Du pkt_dev->dstops.family = AF_INET; 3601cf93d47eSFan Du pkt_dev->dst.dev = pkt_dev->odev; 3602cf93d47eSFan Du dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false); 3603cf93d47eSFan Du pkt_dev->dst.child = &pkt_dev->dst; 3604cf93d47eSFan Du pkt_dev->dst.ops = &pkt_dev->dstops; 3605a553e4a6SJamal Hadi Salim #endif 360639df232fSStephen Hemminger 360739df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 360839df232fSStephen Hemminger out2: 360939df232fSStephen Hemminger dev_put(pkt_dev->odev); 361039df232fSStephen Hemminger out1: 3611a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3612a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3613a553e4a6SJamal Hadi Salim #endif 36141da177e4SLinus Torvalds vfree(pkt_dev->flows); 36151da177e4SLinus Torvalds kfree(pkt_dev); 361639df232fSStephen Hemminger return err; 36171da177e4SLinus Torvalds } 36181da177e4SLinus Torvalds 36194e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) 36201da177e4SLinus Torvalds { 3621cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3622d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3623ee74baa7SDavid S. Miller struct task_struct *p; 36241da177e4SLinus Torvalds 36253291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 36263291b9dbSEric Dumazet cpu_to_node(cpu)); 36271da177e4SLinus Torvalds if (!t) { 3628f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 36291da177e4SLinus Torvalds return -ENOMEM; 36301da177e4SLinus Torvalds } 36311da177e4SLinus Torvalds 36321da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 36331da177e4SLinus Torvalds t->cpu = cpu; 36341da177e4SLinus Torvalds 3635ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3636ee74baa7SDavid S. Miller 36374e58a027SCong Wang list_add_tail(&t->th_list, &pn->pktgen_threads); 3638d3ede327SDenis V. Lunev init_completion(&t->start_done); 3639ee74baa7SDavid S. Miller 364094dcf29aSEric Dumazet p = kthread_create_on_node(pktgen_thread_worker, 364194dcf29aSEric Dumazet t, 364294dcf29aSEric Dumazet cpu_to_node(cpu), 364394dcf29aSEric Dumazet "kpktgend_%d", cpu); 3644ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3645f9467eaeSJoe Perches pr_err("kernel_thread() failed for cpu %d\n", t->cpu); 3646ee74baa7SDavid S. Miller list_del(&t->th_list); 3647ee74baa7SDavid S. Miller kfree(t); 3648ee74baa7SDavid S. Miller return PTR_ERR(p); 3649ee74baa7SDavid S. Miller } 3650ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3651ee74baa7SDavid S. Miller t->tsk = p; 3652ee74baa7SDavid S. Miller 36534e58a027SCong Wang pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir, 36545efdccbcSDenis V. Lunev &pktgen_thread_fops, t); 3655d50a6b56SStephen Hemminger if (!pe) { 3656f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3657ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3658ee74baa7SDavid S. Miller kthread_stop(p); 3659ee74baa7SDavid S. Miller list_del(&t->th_list); 36601da177e4SLinus Torvalds kfree(t); 36611da177e4SLinus Torvalds return -EINVAL; 36621da177e4SLinus Torvalds } 3663d50a6b56SStephen Hemminger 36644e58a027SCong Wang t->net = pn; 3665ee74baa7SDavid S. Miller wake_up_process(p); 3666d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 36671da177e4SLinus Torvalds 36681da177e4SLinus Torvalds return 0; 36691da177e4SLinus Torvalds } 36701da177e4SLinus Torvalds 36711da177e4SLinus Torvalds /* 36721da177e4SLinus Torvalds * Removes a device from the thread if_list. 36731da177e4SLinus Torvalds */ 3674222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3675222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36761da177e4SLinus Torvalds { 3677c26a8016SLuiz Capitulino struct list_head *q, *n; 3678c26a8016SLuiz Capitulino struct pktgen_dev *p; 36791da177e4SLinus Torvalds 36808788370aSJesper Dangaard Brouer if_lock(t); 3681c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3682c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3683c26a8016SLuiz Capitulino if (p == pkt_dev) 36848788370aSJesper Dangaard Brouer list_del_rcu(&p->list); 36851da177e4SLinus Torvalds } 36868788370aSJesper Dangaard Brouer if_unlock(t); 36871da177e4SLinus Torvalds } 36881da177e4SLinus Torvalds 3689222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3690222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36911da177e4SLinus Torvalds { 3692f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 36931da177e4SLinus Torvalds 36941da177e4SLinus Torvalds if (pkt_dev->running) { 3695*294a0b7fSJoe Perches pr_warn("WARNING: trying to remove a running interface, stopping it now\n"); 36961da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 36971da177e4SLinus Torvalds } 36981da177e4SLinus Torvalds 36991da177e4SLinus Torvalds /* Dis-associate from the interface */ 37001da177e4SLinus Torvalds 37011da177e4SLinus Torvalds if (pkt_dev->odev) { 37021da177e4SLinus Torvalds dev_put(pkt_dev->odev); 37031da177e4SLinus Torvalds pkt_dev->odev = NULL; 37041da177e4SLinus Torvalds } 37051da177e4SLinus Torvalds 37068788370aSJesper Dangaard Brouer /* Remove proc before if_list entry, because add_device uses 37078788370aSJesper Dangaard Brouer * list to determine if interface already exist, avoid race 37088788370aSJesper Dangaard Brouer * with proc_create_data() */ 370939df232fSStephen Hemminger if (pkt_dev->entry) 3710a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 37111da177e4SLinus Torvalds 37128788370aSJesper Dangaard Brouer /* And update the thread if_list */ 37138788370aSJesper Dangaard Brouer _rem_dev_from_if_list(t, pkt_dev); 37148788370aSJesper Dangaard Brouer 3715a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3716a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3717a553e4a6SJamal Hadi Salim #endif 37181da177e4SLinus Torvalds vfree(pkt_dev->flows); 371926ad7879SEric Dumazet if (pkt_dev->page) 372026ad7879SEric Dumazet put_page(pkt_dev->page); 37218788370aSJesper Dangaard Brouer kfree_rcu(pkt_dev, rcu); 37221da177e4SLinus Torvalds return 0; 37231da177e4SLinus Torvalds } 37241da177e4SLinus Torvalds 37254e58a027SCong Wang static int __net_init pg_net_init(struct net *net) 37261da177e4SLinus Torvalds { 37274e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3728d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 37294e58a027SCong Wang int cpu, ret = 0; 3730d50a6b56SStephen Hemminger 37314e58a027SCong Wang pn->net = net; 37324e58a027SCong Wang INIT_LIST_HEAD(&pn->pktgen_threads); 37334e58a027SCong Wang pn->pktgen_exiting = false; 37344e58a027SCong Wang pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net); 37354e58a027SCong Wang if (!pn->proc_dir) { 37364e58a027SCong Wang pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); 3737d50a6b56SStephen Hemminger return -ENODEV; 37381da177e4SLinus Torvalds } 37394e58a027SCong Wang pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops); 37404e58a027SCong Wang if (pe == NULL) { 37414e58a027SCong Wang pr_err("cannot create %s procfs entry\n", PGCTRL); 37424e58a027SCong Wang ret = -EINVAL; 37434e58a027SCong Wang goto remove; 37444e58a027SCong Wang } 37451da177e4SLinus Torvalds 3746670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 37478024bb24SLuiz Capitulino int err; 37481da177e4SLinus Torvalds 37494e58a027SCong Wang err = pktgen_create_thread(cpu, pn); 37508024bb24SLuiz Capitulino if (err) 37514e58a027SCong Wang pr_warn("Cannot create thread for cpu %d (%d)\n", 3752f9467eaeSJoe Perches cpu, err); 37531da177e4SLinus Torvalds } 37548024bb24SLuiz Capitulino 37554e58a027SCong Wang if (list_empty(&pn->pktgen_threads)) { 37564e58a027SCong Wang pr_err("Initialization failed for all threads\n"); 3757ce14f894SWANG Cong ret = -ENODEV; 37584e58a027SCong Wang goto remove_entry; 37598024bb24SLuiz Capitulino } 37608024bb24SLuiz Capitulino 37611da177e4SLinus Torvalds return 0; 3762ce14f894SWANG Cong 37634e58a027SCong Wang remove_entry: 37644e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 37654e58a027SCong Wang remove: 3766ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 3767ce14f894SWANG Cong return ret; 37681da177e4SLinus Torvalds } 37691da177e4SLinus Torvalds 37704e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net) 37711da177e4SLinus Torvalds { 37724e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3773cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3774cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 3775d4b11335SEric Dumazet LIST_HEAD(list); 37761da177e4SLinus Torvalds 37771da177e4SLinus Torvalds /* Stop all interfaces & threads */ 37784e58a027SCong Wang pn->pktgen_exiting = true; 37791da177e4SLinus Torvalds 3780c57b5468SEric Dumazet mutex_lock(&pktgen_thread_lock); 37814e58a027SCong Wang list_splice_init(&pn->pktgen_threads, &list); 3782c57b5468SEric Dumazet mutex_unlock(&pktgen_thread_lock); 3783c57b5468SEric Dumazet 3784c57b5468SEric Dumazet list_for_each_safe(q, n, &list) { 3785cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3786c57b5468SEric Dumazet list_del(&t->th_list); 3787ee74baa7SDavid S. Miller kthread_stop(t->tsk); 3788ee74baa7SDavid S. Miller kfree(t); 37891da177e4SLinus Torvalds } 37901da177e4SLinus Torvalds 37914e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 3792ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 37934e58a027SCong Wang } 37941da177e4SLinus Torvalds 37954e58a027SCong Wang static struct pernet_operations pg_net_ops = { 37964e58a027SCong Wang .init = pg_net_init, 37974e58a027SCong Wang .exit = pg_net_exit, 37984e58a027SCong Wang .id = &pg_net_id, 37994e58a027SCong Wang .size = sizeof(struct pktgen_net), 38004e58a027SCong Wang }; 38014e58a027SCong Wang 38024e58a027SCong Wang static int __init pg_init(void) 38034e58a027SCong Wang { 38044e58a027SCong Wang int ret = 0; 38054e58a027SCong Wang 38064e58a027SCong Wang pr_info("%s", version); 38074e58a027SCong Wang ret = register_pernet_subsys(&pg_net_ops); 38084e58a027SCong Wang if (ret) 38094e58a027SCong Wang return ret; 38104e58a027SCong Wang ret = register_netdevice_notifier(&pktgen_notifier_block); 38114e58a027SCong Wang if (ret) 38124e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 38134e58a027SCong Wang 38144e58a027SCong Wang return ret; 38154e58a027SCong Wang } 38164e58a027SCong Wang 38174e58a027SCong Wang static void __exit pg_cleanup(void) 38184e58a027SCong Wang { 38194e58a027SCong Wang unregister_netdevice_notifier(&pktgen_notifier_block); 38204e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 38218788370aSJesper Dangaard Brouer /* Don't need rcu_barrier() due to use of kfree_rcu() */ 38221da177e4SLinus Torvalds } 38231da177e4SLinus Torvalds 38241da177e4SLinus Torvalds module_init(pg_init); 38251da177e4SLinus Torvalds module_exit(pg_cleanup); 38261da177e4SLinus Torvalds 3827c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 38281da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 38291da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3830c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 38311da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3832c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 38331da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3834c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 38351da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3836c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 38371da177e4SLinus Torvalds module_param(debug, int, 0); 3838c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3839