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 * 100ca9f1fd2SStephen Hemminger * Randy Dunlap fixed u64 printk compiler warning 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 18040207264SJesper Dangaard Brouer #define VERSION "2.75" 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 187*6f107c74SDmitry Safonov #define PKT_FLAGS \ 188*6f107c74SDmitry Safonov pf(IPV6) /* Interface in IPV6 Mode */ \ 189*6f107c74SDmitry Safonov pf(IPSRC_RND) /* IP-Src Random */ \ 190*6f107c74SDmitry Safonov pf(IPDST_RND) /* IP-Dst Random */ \ 191*6f107c74SDmitry Safonov pf(TXSIZE_RND) /* Transmit size is random */ \ 192*6f107c74SDmitry Safonov pf(UDPSRC_RND) /* UDP-Src Random */ \ 193*6f107c74SDmitry Safonov pf(UDPDST_RND) /* UDP-Dst Random */ \ 194*6f107c74SDmitry Safonov pf(UDPCSUM) /* Include UDP checksum */ \ 195*6f107c74SDmitry Safonov pf(NO_TIMESTAMP) /* Don't timestamp packets (default TS) */ \ 196*6f107c74SDmitry Safonov pf(MPLS_RND) /* Random MPLS labels */ \ 197*6f107c74SDmitry Safonov pf(QUEUE_MAP_RND) /* queue map Random */ \ 198*6f107c74SDmitry Safonov pf(QUEUE_MAP_CPU) /* queue map mirrors smp_processor_id() */ \ 199*6f107c74SDmitry Safonov pf(FLOW_SEQ) /* Sequential flows */ \ 200*6f107c74SDmitry Safonov pf(IPSEC) /* ipsec on for flows */ \ 201*6f107c74SDmitry Safonov pf(MACSRC_RND) /* MAC-Src Random */ \ 202*6f107c74SDmitry Safonov pf(MACDST_RND) /* MAC-Dst Random */ \ 203*6f107c74SDmitry Safonov pf(VID_RND) /* Random VLAN ID */ \ 204*6f107c74SDmitry Safonov pf(SVID_RND) /* Random SVLAN ID */ \ 205*6f107c74SDmitry Safonov pf(NODE) /* Node memory alloc*/ \ 206*6f107c74SDmitry Safonov 207*6f107c74SDmitry Safonov #define pf(flag) flag##_SHIFT, 208*6f107c74SDmitry Safonov enum pkt_flags { 209*6f107c74SDmitry Safonov PKT_FLAGS 210*6f107c74SDmitry Safonov }; 211*6f107c74SDmitry Safonov #undef pf 212*6f107c74SDmitry Safonov 2131da177e4SLinus Torvalds /* Device flag bits */ 214*6f107c74SDmitry Safonov #define pf(flag) static const __u32 F_##flag = (1<<flag##_SHIFT); 215*6f107c74SDmitry Safonov PKT_FLAGS 216*6f107c74SDmitry Safonov #undef pf 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* Thread control flag bits */ 2196b80d6a6SStephen Hemminger #define T_STOP (1<<0) /* Stop run */ 2206b80d6a6SStephen Hemminger #define T_RUN (1<<1) /* Start run */ 2216b80d6a6SStephen Hemminger #define T_REMDEVALL (1<<2) /* Remove all devs */ 2226b80d6a6SStephen Hemminger #define T_REMDEV (1<<3) /* Remove one dev */ 2231da177e4SLinus Torvalds 22462f64aedSAlexei Starovoitov /* Xmit modes */ 22562f64aedSAlexei Starovoitov #define M_START_XMIT 0 /* Default normal TX */ 22662f64aedSAlexei Starovoitov #define M_NETIF_RECEIVE 1 /* Inject packets into stack */ 2270967f244SJohn Fastabend #define M_QUEUE_XMIT 2 /* Inject packet into qdisc */ 22862f64aedSAlexei Starovoitov 2298788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */ 2309a0b1e8bSEric Dumazet #define if_lock(t) mutex_lock(&(t->if_lock)); 2319a0b1e8bSEric Dumazet #define if_unlock(t) mutex_unlock(&(t->if_lock)); 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 2341da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 235d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen" 236d50a6b56SStephen Hemminger #define PGCTRL "pgctrl" 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds #define MAX_CFLOWS 65536 2391da177e4SLinus Torvalds 24034954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 24134954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 24234954ddcSFrancesco Fondelli 243222f1806SLuiz Capitulino struct flow_state { 244252e3346SAl Viro __be32 cur_daddr; 2451da177e4SLinus Torvalds int count; 246a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 247a553e4a6SJamal Hadi Salim struct xfrm_state *x; 248a553e4a6SJamal Hadi Salim #endif 249007a531bSJamal Hadi Salim __u32 flags; 2501da177e4SLinus Torvalds }; 2511da177e4SLinus Torvalds 252007a531bSJamal Hadi Salim /* flow flag bits */ 253007a531bSJamal Hadi Salim #define F_INIT (1<<0) /* flow has been initialized */ 254007a531bSJamal Hadi Salim 2551da177e4SLinus Torvalds struct pktgen_dev { 2561da177e4SLinus Torvalds /* 2571da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 2581da177e4SLinus Torvalds */ 25939df232fSStephen Hemminger struct proc_dir_entry *entry; /* proc file */ 2601da177e4SLinus Torvalds struct pktgen_thread *pg_thread;/* the owner */ 26163adc6fbSStephen Hemminger struct list_head list; /* chaining in the thread's run-queue */ 2628788370aSJesper Dangaard Brouer struct rcu_head rcu; /* freed by RCU */ 2631da177e4SLinus Torvalds 26463adc6fbSStephen Hemminger int running; /* if false, the test will stop */ 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 2671da177e4SLinus Torvalds * we will do a random selection from within the range. 2681da177e4SLinus Torvalds */ 2691da177e4SLinus Torvalds __u32 flags; 27062f64aedSAlexei Starovoitov int xmit_mode; 27168bf9f0bSAmerigo Wang int min_pkt_size; 27268bf9f0bSAmerigo Wang int max_pkt_size; 27316dab72fSJamal Hadi Salim int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2741da177e4SLinus Torvalds int nfrags; 27562f64aedSAlexei Starovoitov int removal_mark; /* non-zero => the device is marked for 27662f64aedSAlexei Starovoitov * removal by worker thread */ 27762f64aedSAlexei Starovoitov 27826ad7879SEric Dumazet struct page *page; 279fd29cf72SStephen Hemminger u64 delay; /* nano-seconds */ 280fd29cf72SStephen Hemminger 2811da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 2821da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 2831da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 284f466dba1SJohn Fastabend __u64 errors; /* Errors when trying to transmit, */ 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds __u32 clone_count; 2891da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 29063adc6fbSStephen Hemminger * Or a failed transmit of some sort? 29163adc6fbSStephen Hemminger * This will keep sequence numbers in order 2921da177e4SLinus Torvalds */ 293fd29cf72SStephen Hemminger ktime_t next_tx; 294fd29cf72SStephen Hemminger ktime_t started_at; 295fd29cf72SStephen Hemminger ktime_t stopped_at; 296fd29cf72SStephen Hemminger u64 idle_acc; /* nano-seconds */ 297fd29cf72SStephen Hemminger 2981da177e4SLinus Torvalds __u32 seq_num; 2991da177e4SLinus Torvalds 30063adc6fbSStephen Hemminger int clone_skb; /* 30163adc6fbSStephen Hemminger * Use multiple SKBs during packet gen. 30263adc6fbSStephen Hemminger * If this number is greater than 1, then 30363adc6fbSStephen Hemminger * that many copies of the same packet will be 30463adc6fbSStephen Hemminger * sent before a new packet is allocated. 30563adc6fbSStephen Hemminger * If you want to send 1024 identical packets 30663adc6fbSStephen Hemminger * before creating a new packet, 30763adc6fbSStephen Hemminger * set clone_skb to 1024. 3081da177e4SLinus Torvalds */ 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3111da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3121da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3131da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds struct in6_addr in6_saddr; 3161da177e4SLinus Torvalds struct in6_addr in6_daddr; 3171da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 3181da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 3191da177e4SLinus Torvalds /* For ranges */ 3201da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 3211da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 3221da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 3231da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 3261da177e4SLinus Torvalds * defines the min/max for those ranges. 3271da177e4SLinus Torvalds */ 328252e3346SAl Viro __be32 saddr_min; /* inclusive, source IP address */ 329252e3346SAl Viro __be32 saddr_max; /* exclusive, source IP address */ 330252e3346SAl Viro __be32 daddr_min; /* inclusive, dest IP address */ 331252e3346SAl Viro __be32 daddr_max; /* exclusive, dest IP address */ 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 3341da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 3351da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 3361da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 3371da177e4SLinus Torvalds 3381ca7768cSFrancesco Fondelli /* DSCP + ECN */ 33963adc6fbSStephen Hemminger __u8 tos; /* six MSB of (former) IPv4 TOS 34063adc6fbSStephen Hemminger are for dscp codepoint */ 34163adc6fbSStephen Hemminger __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 34263adc6fbSStephen Hemminger (see RFC 3260, sec. 4) */ 3431ca7768cSFrancesco Fondelli 344ca6549afSSteven Whitehouse /* MPLS */ 34595c96174SEric Dumazet unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */ 346ca6549afSSteven Whitehouse __be32 labels[MAX_MPLS_LABELS]; 347ca6549afSSteven Whitehouse 34834954ddcSFrancesco Fondelli /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 34934954ddcSFrancesco Fondelli __u8 vlan_p; 35034954ddcSFrancesco Fondelli __u8 vlan_cfi; 35134954ddcSFrancesco Fondelli __u16 vlan_id; /* 0xffff means no vlan tag */ 35234954ddcSFrancesco Fondelli 35334954ddcSFrancesco Fondelli __u8 svlan_p; 35434954ddcSFrancesco Fondelli __u8 svlan_cfi; 35534954ddcSFrancesco Fondelli __u16 svlan_id; /* 0xffff means no svlan tag */ 35634954ddcSFrancesco Fondelli 3571da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 3581da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 3591da177e4SLinus Torvalds 360f404e9a6SKris Katterjohn unsigned char dst_mac[ETH_ALEN]; 361f404e9a6SKris Katterjohn unsigned char src_mac[ETH_ALEN]; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 3641da177e4SLinus Torvalds __u32 cur_src_mac_offset; 365252e3346SAl Viro __be32 cur_saddr; 366252e3346SAl Viro __be32 cur_daddr; 36766ed1e5eSEric Dumazet __u16 ip_id; 3681da177e4SLinus Torvalds __u16 cur_udp_dst; 3691da177e4SLinus Torvalds __u16 cur_udp_src; 37045b270f8SRobert Olsson __u16 cur_queue_map; 3711da177e4SLinus Torvalds __u32 cur_pkt_size; 372baac8564SEric Dumazet __u32 last_pkt_size; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds __u8 hh[14]; 3751da177e4SLinus Torvalds /* = { 3761da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds We fill in SRC address later 3791da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3801da177e4SLinus Torvalds 0x08, 0x00 3811da177e4SLinus Torvalds }; 3821da177e4SLinus Torvalds */ 3831da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 3841da177e4SLinus Torvalds 38563adc6fbSStephen Hemminger struct sk_buff *skb; /* skb we are to transmit next, used for when we 3861da177e4SLinus Torvalds * are transmitting the same one multiple times 3871da177e4SLinus Torvalds */ 38863adc6fbSStephen Hemminger struct net_device *odev; /* The out-going device. 38963adc6fbSStephen Hemminger * Note that the device should have it's 39063adc6fbSStephen Hemminger * pg_info pointer pointing back to this 39163adc6fbSStephen Hemminger * device. 39263adc6fbSStephen Hemminger * Set when the user specifies the out-going 39363adc6fbSStephen Hemminger * device name (not when the inject is 3941da177e4SLinus Torvalds * started as it used to do.) 3951da177e4SLinus Torvalds */ 396593f63b0SEric Dumazet char odevname[32]; 3971da177e4SLinus Torvalds struct flow_state *flows; 39895c96174SEric Dumazet unsigned int cflows; /* Concurrent flows (config) */ 39995c96174SEric Dumazet unsigned int lflow; /* Flow length (config) */ 40095c96174SEric Dumazet unsigned int nflows; /* accumulated flows (stats) */ 40195c96174SEric Dumazet unsigned int curfl; /* current sequenced flow (state)*/ 40245b270f8SRobert Olsson 40345b270f8SRobert Olsson u16 queue_map_min; 40445b270f8SRobert Olsson u16 queue_map_max; 4059e50e3acSJohn Fastabend __u32 skb_priority; /* skb priority field */ 40638b2cf29SAlexei Starovoitov unsigned int burst; /* number of duplicated packets to burst */ 407e99b99b4SRobert Olsson int node; /* Memory node */ 40845b270f8SRobert Olsson 409a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 410a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 411a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 412de4aee7dSFan Du __u32 spi; 413b6ca8bd5SDavid Miller struct xfrm_dst xdst; 414cf93d47eSFan Du struct dst_ops dstops; 415a553e4a6SJamal Hadi Salim #endif 41639df232fSStephen Hemminger char result[512]; 4171da177e4SLinus Torvalds }; 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds struct pktgen_hdr { 420252e3346SAl Viro __be32 pgh_magic; 421252e3346SAl Viro __be32 seq_num; 422252e3346SAl Viro __be32 tv_sec; 423252e3346SAl Viro __be32 tv_usec; 4241da177e4SLinus Torvalds }; 4251da177e4SLinus Torvalds 4264e58a027SCong Wang 427c7d03a00SAlexey Dobriyan static unsigned int pg_net_id __read_mostly; 4284e58a027SCong Wang 4294e58a027SCong Wang struct pktgen_net { 4304e58a027SCong Wang struct net *net; 4314e58a027SCong Wang struct proc_dir_entry *proc_dir; 4324e58a027SCong Wang struct list_head pktgen_threads; 4334e58a027SCong Wang bool pktgen_exiting; 4344e58a027SCong Wang }; 435551eaff1SEric Dumazet 4361da177e4SLinus Torvalds struct pktgen_thread { 4379a0b1e8bSEric Dumazet struct mutex if_lock; /* for list of devices */ 438c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 439cdcdbe0bSLuiz Capitulino struct list_head th_list; 440ee74baa7SDavid S. Miller struct task_struct *tsk; 4411da177e4SLinus Torvalds char result[512]; 4421da177e4SLinus Torvalds 44363adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 44463adc6fbSStephen Hemminger stop ifs etc. */ 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds u32 control; 4471da177e4SLinus Torvalds int cpu; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds wait_queue_head_t queue; 450d3ede327SDenis V. Lunev struct completion start_done; 4514e58a027SCong Wang struct pktgen_net *net; 4521da177e4SLinus Torvalds }; 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds #define REMOVE 1 4551da177e4SLinus Torvalds #define FIND 0 4561da177e4SLinus Torvalds 457c3d2f52dSStephen Hemminger static const char version[] = 458f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 459f9467eaeSJoe Perches "Version: " VERSION "\n"; 4601da177e4SLinus Torvalds 4611da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4621da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 463222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4643e984840SEric Dumazet const char *ifname, bool exact); 4651da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4664e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn); 4674e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn); 4684e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn); 4693bda06a3SStephen Hemminger 4701da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4711da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 47239df232fSStephen Hemminger 4731da177e4SLinus Torvalds /* Module parameters, defaults. */ 47465c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 47565c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 47665c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 47765c5b786SStephen Hemminger static int debug __read_mostly; 4781da177e4SLinus Torvalds 479222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 4821da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 4831da177e4SLinus Torvalds }; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds /* 4861da177e4SLinus Torvalds * /proc handling functions 4871da177e4SLinus Torvalds * 4881da177e4SLinus Torvalds */ 4891da177e4SLinus Torvalds 490d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 491d50a6b56SStephen Hemminger { 492c3d2f52dSStephen Hemminger seq_puts(seq, version); 493d50a6b56SStephen Hemminger return 0; 494d50a6b56SStephen Hemminger } 4951da177e4SLinus Torvalds 496d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 4971da177e4SLinus Torvalds size_t count, loff_t *ppos) 4981da177e4SLinus Torvalds { 499d50a6b56SStephen Hemminger char data[128]; 5004e58a027SCong Wang struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id); 5011da177e4SLinus Torvalds 50209455747SMathias Krause if (!capable(CAP_NET_ADMIN)) 50309455747SMathias Krause return -EPERM; 5041da177e4SLinus Torvalds 50520b0c718SMathias Krause if (count == 0) 50620b0c718SMathias Krause return -EINVAL; 50720b0c718SMathias Krause 508d50a6b56SStephen Hemminger if (count > sizeof(data)) 509d50a6b56SStephen Hemminger count = sizeof(data); 5101da177e4SLinus Torvalds 51109455747SMathias Krause if (copy_from_user(data, buf, count)) 51209455747SMathias Krause return -EFAULT; 51309455747SMathias Krause 51420b0c718SMathias Krause data[count - 1] = 0; /* Strip trailing '\n' and terminate string */ 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds if (!strcmp(data, "stop")) 5174e58a027SCong Wang pktgen_stop_all_threads_ifs(pn); 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds else if (!strcmp(data, "start")) 5204e58a027SCong Wang pktgen_run_all_threads(pn); 5211da177e4SLinus Torvalds 522eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 5234e58a027SCong Wang pktgen_reset_all_threads(pn); 524eb37b41cSJesse Brandeburg 5251da177e4SLinus Torvalds else 52640207264SJesper Dangaard Brouer return -EINVAL; 5271da177e4SLinus Torvalds 52809455747SMathias Krause return count; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 531d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5321da177e4SLinus Torvalds { 533d9dda78bSAl Viro return single_open(file, pgctrl_show, PDE_DATA(inode)); 534d50a6b56SStephen Hemminger } 535d50a6b56SStephen Hemminger 5369a32144eSArjan van de Ven static const struct file_operations pktgen_fops = { 537d50a6b56SStephen Hemminger .open = pgctrl_open, 538d50a6b56SStephen Hemminger .read = seq_read, 539d50a6b56SStephen Hemminger .llseek = seq_lseek, 540d50a6b56SStephen Hemminger .write = pgctrl_write, 541d50a6b56SStephen Hemminger .release = single_release, 542d50a6b56SStephen Hemminger }; 543d50a6b56SStephen Hemminger 544d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 545d50a6b56SStephen Hemminger { 546648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 547fd29cf72SStephen Hemminger ktime_t stopped; 548fd29cf72SStephen Hemminger u64 idle; 5491da177e4SLinus Torvalds 550222f1806SLuiz Capitulino seq_printf(seq, 551222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 552222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 553222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5541da177e4SLinus Torvalds 555222f1806SLuiz Capitulino seq_printf(seq, 556fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 557fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 558593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5591da177e4SLinus Torvalds 560222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 561222f1806SLuiz Capitulino pkt_dev->lflow); 5621da177e4SLinus Torvalds 56345b270f8SRobert Olsson seq_printf(seq, 56445b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 56545b270f8SRobert Olsson pkt_dev->queue_map_min, 56645b270f8SRobert Olsson pkt_dev->queue_map_max); 56745b270f8SRobert Olsson 5689e50e3acSJohn Fastabend if (pkt_dev->skb_priority) 5699e50e3acSJohn Fastabend seq_printf(seq, " skb_priority: %u\n", 5709e50e3acSJohn Fastabend pkt_dev->skb_priority); 5719e50e3acSJohn Fastabend 5721da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 573222f1806SLuiz Capitulino seq_printf(seq, 57447a0200dSAlexey Dobriyan " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" 57547a0200dSAlexey Dobriyan " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", 57647a0200dSAlexey Dobriyan &pkt_dev->in6_saddr, 57747a0200dSAlexey Dobriyan &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, 57847a0200dSAlexey Dobriyan &pkt_dev->in6_daddr, 57947a0200dSAlexey Dobriyan &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); 58063adc6fbSStephen Hemminger } else { 581222f1806SLuiz Capitulino seq_printf(seq, 58263adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 58363adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 58463adc6fbSStephen Hemminger seq_printf(seq, 58563adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 58663adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 58763adc6fbSStephen Hemminger } 5881da177e4SLinus Torvalds 589d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 5901da177e4SLinus Torvalds 591e174961cSJohannes Berg seq_printf(seq, "%pM ", 592e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 593e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5941da177e4SLinus Torvalds 59597dc48e2SThomas Graf seq_puts(seq, "dst_mac: "); 596e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 5971da177e4SLinus Torvalds 598222f1806SLuiz Capitulino seq_printf(seq, 59963adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 60063adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 601222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 602222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 6031da177e4SLinus Torvalds 604222f1806SLuiz Capitulino seq_printf(seq, 605ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 6061da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 6071da177e4SLinus Torvalds 608ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 60995c96174SEric Dumazet unsigned int i; 61097dc48e2SThomas Graf seq_puts(seq, " mpls: "); 611ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 612ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 613ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 614ca6549afSSteven Whitehouse } 615ca6549afSSteven Whitehouse 61663adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 61734954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 61863adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 61963adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 62034954ddcSFrancesco Fondelli 62163adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 62234954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 62363adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 62463adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 62534954ddcSFrancesco Fondelli 62663adc6fbSStephen Hemminger if (pkt_dev->tos) 6271ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6281ca7768cSFrancesco Fondelli 62963adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6301ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6311ca7768cSFrancesco Fondelli 63238b2cf29SAlexei Starovoitov if (pkt_dev->burst > 1) 63338b2cf29SAlexei Starovoitov seq_printf(seq, " burst: %d\n", pkt_dev->burst); 63438b2cf29SAlexei Starovoitov 635e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 636e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 637e99b99b4SRobert Olsson 63862f64aedSAlexei Starovoitov if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) 63962f64aedSAlexei Starovoitov seq_puts(seq, " xmit_mode: netif_receive\n"); 6400967f244SJohn Fastabend else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) 6410967f244SJohn Fastabend seq_puts(seq, " xmit_mode: xmit_queue\n"); 64262f64aedSAlexei Starovoitov 64397dc48e2SThomas Graf seq_puts(seq, " Flags: "); 644ca6549afSSteven Whitehouse 6451da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 64697dc48e2SThomas Graf seq_puts(seq, "IPV6 "); 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 64997dc48e2SThomas Graf seq_puts(seq, "IPSRC_RND "); 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 65297dc48e2SThomas Graf seq_puts(seq, "IPDST_RND "); 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 65597dc48e2SThomas Graf seq_puts(seq, "TXSIZE_RND "); 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 65897dc48e2SThomas Graf seq_puts(seq, "UDPSRC_RND "); 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 66197dc48e2SThomas Graf seq_puts(seq, "UDPDST_RND "); 6621da177e4SLinus Torvalds 663c26bf4a5SThomas Graf if (pkt_dev->flags & F_UDPCSUM) 66497dc48e2SThomas Graf seq_puts(seq, "UDPCSUM "); 665c26bf4a5SThomas Graf 666afb84b62SJesper Dangaard Brouer if (pkt_dev->flags & F_NO_TIMESTAMP) 667afb84b62SJesper Dangaard Brouer seq_puts(seq, "NO_TIMESTAMP "); 668afb84b62SJesper Dangaard Brouer 669ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) 67097dc48e2SThomas Graf seq_puts(seq, "MPLS_RND "); 671ca6549afSSteven Whitehouse 67245b270f8SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_RND) 67397dc48e2SThomas Graf seq_puts(seq, "QUEUE_MAP_RND "); 67445b270f8SRobert Olsson 675e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 67697dc48e2SThomas Graf seq_puts(seq, "QUEUE_MAP_CPU "); 677e6fce5b9SRobert Olsson 678007a531bSJamal Hadi Salim if (pkt_dev->cflows) { 679007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) 68097dc48e2SThomas Graf seq_puts(seq, "FLOW_SEQ "); /*in sequence flows*/ 681007a531bSJamal Hadi Salim else 68297dc48e2SThomas Graf seq_puts(seq, "FLOW_RND "); 683007a531bSJamal Hadi Salim } 684007a531bSJamal Hadi Salim 685a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 686*6f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) { 68797dc48e2SThomas Graf seq_puts(seq, "IPSEC "); 6888101328bSFan Du if (pkt_dev->spi) 6898101328bSFan Du seq_printf(seq, "spi:%u", pkt_dev->spi); 6908101328bSFan Du } 691a553e4a6SJamal Hadi Salim #endif 692a553e4a6SJamal Hadi Salim 6931da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 69497dc48e2SThomas Graf seq_puts(seq, "MACSRC_RND "); 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 69797dc48e2SThomas Graf seq_puts(seq, "MACDST_RND "); 6981da177e4SLinus Torvalds 69934954ddcSFrancesco Fondelli if (pkt_dev->flags & F_VID_RND) 70097dc48e2SThomas Graf seq_puts(seq, "VID_RND "); 70134954ddcSFrancesco Fondelli 70234954ddcSFrancesco Fondelli if (pkt_dev->flags & F_SVID_RND) 70397dc48e2SThomas Graf seq_puts(seq, "SVID_RND "); 70434954ddcSFrancesco Fondelli 705e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) 70697dc48e2SThomas Graf seq_puts(seq, "NODE_ALLOC "); 707e99b99b4SRobert Olsson 708d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 7091da177e4SLinus Torvalds 710fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 711398f382cSDaniel Borkmann stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at; 712fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 713fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 7141da177e4SLinus Torvalds 715222f1806SLuiz Capitulino seq_printf(seq, 716fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 7171da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 718fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 719fd29cf72SStephen Hemminger 720fd29cf72SStephen Hemminger seq_printf(seq, 721fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 722fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 723fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 724fd29cf72SStephen Hemminger (unsigned long long) idle); 7251da177e4SLinus Torvalds 726222f1806SLuiz Capitulino seq_printf(seq, 727222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 728d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 729d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 73247a0200dSAlexey Dobriyan seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", 73347a0200dSAlexey Dobriyan &pkt_dev->cur_in6_saddr, 73447a0200dSAlexey Dobriyan &pkt_dev->cur_in6_daddr); 735222f1806SLuiz Capitulino } else 7360373a946SAmerigo Wang seq_printf(seq, " cur_saddr: %pI4 cur_daddr: %pI4\n", 7370373a946SAmerigo Wang &pkt_dev->cur_saddr, &pkt_dev->cur_daddr); 7381da177e4SLinus Torvalds 739d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7401da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7411da177e4SLinus Torvalds 74245b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 74345b270f8SRobert Olsson 744d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds if (pkt_dev->result[0]) 747d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7481da177e4SLinus Torvalds else 74997dc48e2SThomas Graf seq_puts(seq, "Result: Idle\n"); 7501da177e4SLinus Torvalds 751d50a6b56SStephen Hemminger return 0; 7521da177e4SLinus Torvalds } 7531da177e4SLinus Torvalds 754ca6549afSSteven Whitehouse 75563adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 75663adc6fbSStephen Hemminger __u32 *num) 757ca6549afSSteven Whitehouse { 758ca6549afSSteven Whitehouse int i = 0; 759ca6549afSSteven Whitehouse *num = 0; 760ca6549afSSteven Whitehouse 7611ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 76282fd5b5dSAndy Shevchenko int value; 763ca6549afSSteven Whitehouse char c; 764ca6549afSSteven Whitehouse *num <<= 4; 765ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 766ca6549afSSteven Whitehouse return -EFAULT; 76782fd5b5dSAndy Shevchenko value = hex_to_bin(c); 76882fd5b5dSAndy Shevchenko if (value >= 0) 76982fd5b5dSAndy Shevchenko *num |= value; 770ca6549afSSteven Whitehouse else 771ca6549afSSteven Whitehouse break; 772ca6549afSSteven Whitehouse } 773ca6549afSSteven Whitehouse return i; 774ca6549afSSteven Whitehouse } 775ca6549afSSteven Whitehouse 776222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 777222f1806SLuiz Capitulino unsigned int maxlen) 7781da177e4SLinus Torvalds { 7791da177e4SLinus Torvalds int i; 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7821da177e4SLinus Torvalds char c; 7831da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7841da177e4SLinus Torvalds return -EFAULT; 7851da177e4SLinus Torvalds switch (c) { 7861da177e4SLinus Torvalds case '\"': 7871da177e4SLinus Torvalds case '\n': 7881da177e4SLinus Torvalds case '\r': 7891da177e4SLinus Torvalds case '\t': 7901da177e4SLinus Torvalds case ' ': 7911da177e4SLinus Torvalds case '=': 7921da177e4SLinus Torvalds break; 7931da177e4SLinus Torvalds default: 7941da177e4SLinus Torvalds goto done; 7953ff50b79SStephen Hemminger } 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds done: 7981da177e4SLinus Torvalds return i; 7991da177e4SLinus Torvalds } 8001da177e4SLinus Torvalds 801bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen, 802bf0813bdSPaul Gortmaker unsigned long *num) 8031da177e4SLinus Torvalds { 804d6182223SPaul Gortmaker int i; 8051da177e4SLinus Torvalds *num = 0; 8061da177e4SLinus Torvalds 807d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 8081da177e4SLinus Torvalds char c; 8091da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8101da177e4SLinus Torvalds return -EFAULT; 8111da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 8121da177e4SLinus Torvalds *num *= 10; 8131da177e4SLinus Torvalds *num += c - '0'; 8141da177e4SLinus Torvalds } else 8151da177e4SLinus Torvalds break; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds return i; 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 8211da177e4SLinus Torvalds { 822d6182223SPaul Gortmaker int i; 8231da177e4SLinus Torvalds 824d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 8251da177e4SLinus Torvalds char c; 8261da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8271da177e4SLinus Torvalds return -EFAULT; 8281da177e4SLinus Torvalds switch (c) { 8291da177e4SLinus Torvalds case '\"': 8301da177e4SLinus Torvalds case '\n': 8311da177e4SLinus Torvalds case '\r': 8321da177e4SLinus Torvalds case '\t': 8331da177e4SLinus Torvalds case ' ': 8341da177e4SLinus Torvalds goto done_str; 8351da177e4SLinus Torvalds default: 8361da177e4SLinus Torvalds break; 8373ff50b79SStephen Hemminger } 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds done_str: 8401da177e4SLinus Torvalds return i; 8411da177e4SLinus Torvalds } 8421da177e4SLinus Torvalds 843ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 844ca6549afSSteven Whitehouse { 84595c96174SEric Dumazet unsigned int n = 0; 846ca6549afSSteven Whitehouse char c; 847ca6549afSSteven Whitehouse ssize_t i = 0; 848ca6549afSSteven Whitehouse int len; 849ca6549afSSteven Whitehouse 850ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 851ca6549afSSteven Whitehouse do { 852ca6549afSSteven Whitehouse __u32 tmp; 8531ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 854ca6549afSSteven Whitehouse if (len <= 0) 855ca6549afSSteven Whitehouse return len; 856ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 857ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 858ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 859ca6549afSSteven Whitehouse i += len; 860ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 861ca6549afSSteven Whitehouse return -EFAULT; 862ca6549afSSteven Whitehouse i++; 863ca6549afSSteven Whitehouse n++; 864ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 865ca6549afSSteven Whitehouse return -E2BIG; 866ca6549afSSteven Whitehouse } while (c == ','); 867ca6549afSSteven Whitehouse 868ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 869ca6549afSSteven Whitehouse return i; 870ca6549afSSteven Whitehouse } 871ca6549afSSteven Whitehouse 872222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 873222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 874222f1806SLuiz Capitulino loff_t * offset) 8751da177e4SLinus Torvalds { 8768a994a71SJoe Perches struct seq_file *seq = file->private_data; 877d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 878d6182223SPaul Gortmaker int i, max, len; 8791da177e4SLinus Torvalds char name[16], valstr[32]; 8801da177e4SLinus Torvalds unsigned long value = 0; 8811da177e4SLinus Torvalds char *pg_result = NULL; 8821da177e4SLinus Torvalds int tmp = 0; 8831da177e4SLinus Torvalds char buf[128]; 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds if (count < 1) { 888294a0b7fSJoe Perches pr_warn("wrong command format\n"); 8891da177e4SLinus Torvalds return -EINVAL; 8901da177e4SLinus Torvalds } 8911da177e4SLinus Torvalds 892d6182223SPaul Gortmaker max = count; 893d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 8941da177e4SLinus Torvalds if (tmp < 0) { 895294a0b7fSJoe Perches pr_warn("illegal format\n"); 8961da177e4SLinus Torvalds return tmp; 8971da177e4SLinus Torvalds } 898d6182223SPaul Gortmaker i = tmp; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds /* Read variable name */ 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 90363adc6fbSStephen Hemminger if (len < 0) 904222f1806SLuiz Capitulino return len; 90563adc6fbSStephen Hemminger 9061da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 9071da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 9081da177e4SLinus Torvalds return -EFAULT; 9091da177e4SLinus Torvalds i += len; 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds max = count - i; 9121da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 9131da177e4SLinus Torvalds if (len < 0) 9141da177e4SLinus Torvalds return len; 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds i += len; 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds if (debug) { 91986c2c0a8SDmitry Torokhov size_t copy = min_t(size_t, count, 1023); 920448d7b5dSNelson Elhage char tb[copy + 1]; 921448d7b5dSNelson Elhage if (copy_from_user(tb, user_buffer, copy)) 9221da177e4SLinus Torvalds return -EFAULT; 923448d7b5dSNelson Elhage tb[copy] = 0; 924f342cda7SJoe Perches pr_debug("%s,%lu buffer -:%s:-\n", 925f342cda7SJoe Perches name, (unsigned long)count, tb); 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9291da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 93063adc6fbSStephen Hemminger if (len < 0) 931222f1806SLuiz Capitulino return len; 93263adc6fbSStephen Hemminger 9331da177e4SLinus Torvalds i += len; 9341da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9351da177e4SLinus Torvalds value = 14 + 20 + 8; 9361da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9371da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9381da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9391da177e4SLinus Torvalds } 940222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 941222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9421da177e4SLinus Torvalds return count; 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9461da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 94763adc6fbSStephen Hemminger if (len < 0) 948222f1806SLuiz Capitulino return len; 94963adc6fbSStephen Hemminger 9501da177e4SLinus Torvalds i += len; 9511da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9521da177e4SLinus Torvalds value = 14 + 20 + 8; 9531da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9541da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9551da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9561da177e4SLinus Torvalds } 957222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 958222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9591da177e4SLinus Torvalds return count; 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds /* Shortcut for min = max */ 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9651da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 96663adc6fbSStephen Hemminger if (len < 0) 967222f1806SLuiz Capitulino return len; 96863adc6fbSStephen Hemminger 9691da177e4SLinus Torvalds i += len; 9701da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9711da177e4SLinus Torvalds value = 14 + 20 + 8; 9721da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9731da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9741da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9751da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9761da177e4SLinus Torvalds } 9771da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 9781da177e4SLinus Torvalds return count; 9791da177e4SLinus Torvalds } 9801da177e4SLinus Torvalds 9811da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9821da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 98363adc6fbSStephen Hemminger if (len < 0) 984222f1806SLuiz Capitulino return len; 98563adc6fbSStephen Hemminger 9861da177e4SLinus Torvalds i += len; 9871da177e4SLinus Torvalds debug = value; 9881da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9891da177e4SLinus Torvalds return count; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9931da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 99463adc6fbSStephen Hemminger if (len < 0) 995222f1806SLuiz Capitulino return len; 99663adc6fbSStephen Hemminger 9971da177e4SLinus Torvalds i += len; 9981da177e4SLinus Torvalds pkt_dev->nfrags = value; 9991da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 10001da177e4SLinus Torvalds return count; 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 10031da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 100463adc6fbSStephen Hemminger if (len < 0) 1005222f1806SLuiz Capitulino return len; 100663adc6fbSStephen Hemminger 10071da177e4SLinus Torvalds i += len; 1008fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 1009fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 1010fd29cf72SStephen Hemminger else 10119240d715SEric Dumazet pkt_dev->delay = (u64)value; 1012fd29cf72SStephen Hemminger 1013fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 1014fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 10151da177e4SLinus Torvalds return count; 10161da177e4SLinus Torvalds } 101743d28b65SDaniel Turull if (!strcmp(name, "rate")) { 101843d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 101943d28b65SDaniel Turull if (len < 0) 102043d28b65SDaniel Turull return len; 102143d28b65SDaniel Turull 102243d28b65SDaniel Turull i += len; 102343d28b65SDaniel Turull if (!value) 102443d28b65SDaniel Turull return len; 102543d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 102643d28b65SDaniel Turull if (debug) 1027f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 102843d28b65SDaniel Turull 102943d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 103043d28b65SDaniel Turull return count; 103143d28b65SDaniel Turull } 103243d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 103343d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 103443d28b65SDaniel Turull if (len < 0) 103543d28b65SDaniel Turull return len; 103643d28b65SDaniel Turull 103743d28b65SDaniel Turull i += len; 103843d28b65SDaniel Turull if (!value) 103943d28b65SDaniel Turull return len; 104043d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 104143d28b65SDaniel Turull if (debug) 1042f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 104343d28b65SDaniel Turull 104443d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 104543d28b65SDaniel Turull return count; 104643d28b65SDaniel Turull } 10471da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10481da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 104963adc6fbSStephen Hemminger if (len < 0) 1050222f1806SLuiz Capitulino return len; 105163adc6fbSStephen Hemminger 10521da177e4SLinus Torvalds i += len; 10531da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10541da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10551da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10561da177e4SLinus Torvalds } 10571da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10581da177e4SLinus Torvalds return count; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10611da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 106263adc6fbSStephen Hemminger if (len < 0) 1063222f1806SLuiz Capitulino return len; 106463adc6fbSStephen Hemminger 10651da177e4SLinus Torvalds i += len; 10661da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10671da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10681da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10691da177e4SLinus Torvalds } 10701da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10711da177e4SLinus Torvalds return count; 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10741da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107563adc6fbSStephen Hemminger if (len < 0) 1076222f1806SLuiz Capitulino return len; 107763adc6fbSStephen Hemminger 10781da177e4SLinus Torvalds i += len; 10791da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10801da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10811da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10821da177e4SLinus Torvalds } 10831da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10841da177e4SLinus Torvalds return count; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10871da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 108863adc6fbSStephen Hemminger if (len < 0) 1089222f1806SLuiz Capitulino return len; 109063adc6fbSStephen Hemminger 10911da177e4SLinus Torvalds i += len; 10921da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10931da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10941da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10951da177e4SLinus Torvalds } 10961da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10971da177e4SLinus Torvalds return count; 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 11001da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 110163adc6fbSStephen Hemminger if (len < 0) 1102222f1806SLuiz Capitulino return len; 1103d8873315SNeil Horman if ((value > 0) && 110462f64aedSAlexei Starovoitov ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) || 110562f64aedSAlexei Starovoitov !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) 1106d8873315SNeil Horman return -ENOTSUPP; 11071da177e4SLinus Torvalds i += len; 11081da177e4SLinus Torvalds pkt_dev->clone_skb = value; 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 11111da177e4SLinus Torvalds return count; 11121da177e4SLinus Torvalds } 11131da177e4SLinus Torvalds if (!strcmp(name, "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 pkt_dev->count = value; 11201da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 11211da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 11221da177e4SLinus Torvalds return count; 11231da177e4SLinus Torvalds } 11241da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 11251da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 112663adc6fbSStephen Hemminger if (len < 0) 1127222f1806SLuiz Capitulino return len; 112863adc6fbSStephen Hemminger 11291da177e4SLinus Torvalds i += len; 11301da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 11311da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11321da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11331da177e4SLinus Torvalds } 1134222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1135222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11361da177e4SLinus Torvalds return count; 11371da177e4SLinus Torvalds } 11381da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11391da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 114063adc6fbSStephen Hemminger if (len < 0) 1141222f1806SLuiz Capitulino return len; 114263adc6fbSStephen Hemminger 11431da177e4SLinus Torvalds i += len; 11441da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11451da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11461da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11471da177e4SLinus Torvalds } 1148222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1149222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11501da177e4SLinus Torvalds return count; 11511da177e4SLinus Torvalds } 115238b2cf29SAlexei Starovoitov if (!strcmp(name, "burst")) { 115338b2cf29SAlexei Starovoitov len = num_arg(&user_buffer[i], 10, &value); 115438b2cf29SAlexei Starovoitov if (len < 0) 115538b2cf29SAlexei Starovoitov return len; 115638b2cf29SAlexei Starovoitov 115738b2cf29SAlexei Starovoitov i += len; 11580967f244SJohn Fastabend if ((value > 1) && 11590967f244SJohn Fastabend ((pkt_dev->xmit_mode == M_QUEUE_XMIT) || 11600967f244SJohn Fastabend ((pkt_dev->xmit_mode == M_START_XMIT) && 11610967f244SJohn Fastabend (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))))) 116252d6c8c6SEric Dumazet return -ENOTSUPP; 116338b2cf29SAlexei Starovoitov pkt_dev->burst = value < 1 ? 1 : value; 116438b2cf29SAlexei Starovoitov sprintf(pg_result, "OK: burst=%d", pkt_dev->burst); 116538b2cf29SAlexei Starovoitov return count; 116638b2cf29SAlexei Starovoitov } 1167e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1168e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1169e99b99b4SRobert Olsson if (len < 0) 1170e99b99b4SRobert Olsson return len; 1171e99b99b4SRobert Olsson 1172e99b99b4SRobert Olsson i += len; 1173e99b99b4SRobert Olsson 1174e99b99b4SRobert Olsson if (node_possible(value)) { 1175e99b99b4SRobert Olsson pkt_dev->node = value; 1176e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 117726ad7879SEric Dumazet if (pkt_dev->page) { 117826ad7879SEric Dumazet put_page(pkt_dev->page); 117926ad7879SEric Dumazet pkt_dev->page = NULL; 118026ad7879SEric Dumazet } 1181e99b99b4SRobert Olsson } 1182e99b99b4SRobert Olsson else 1183e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1184e99b99b4SRobert Olsson return count; 1185e99b99b4SRobert Olsson } 118662f64aedSAlexei Starovoitov if (!strcmp(name, "xmit_mode")) { 118762f64aedSAlexei Starovoitov char f[32]; 118862f64aedSAlexei Starovoitov 118962f64aedSAlexei Starovoitov memset(f, 0, 32); 119062f64aedSAlexei Starovoitov len = strn_len(&user_buffer[i], sizeof(f) - 1); 119162f64aedSAlexei Starovoitov if (len < 0) 119262f64aedSAlexei Starovoitov return len; 119362f64aedSAlexei Starovoitov 119462f64aedSAlexei Starovoitov if (copy_from_user(f, &user_buffer[i], len)) 119562f64aedSAlexei Starovoitov return -EFAULT; 119662f64aedSAlexei Starovoitov i += len; 119762f64aedSAlexei Starovoitov 119862f64aedSAlexei Starovoitov if (strcmp(f, "start_xmit") == 0) { 119962f64aedSAlexei Starovoitov pkt_dev->xmit_mode = M_START_XMIT; 120062f64aedSAlexei Starovoitov } else if (strcmp(f, "netif_receive") == 0) { 120162f64aedSAlexei Starovoitov /* clone_skb set earlier, not supported in this mode */ 120262f64aedSAlexei Starovoitov if (pkt_dev->clone_skb > 0) 120362f64aedSAlexei Starovoitov return -ENOTSUPP; 120462f64aedSAlexei Starovoitov 120562f64aedSAlexei Starovoitov pkt_dev->xmit_mode = M_NETIF_RECEIVE; 12069eea9222SAlexei Starovoitov 12079eea9222SAlexei Starovoitov /* make sure new packet is allocated every time 12089eea9222SAlexei Starovoitov * pktgen_xmit() is called 12099eea9222SAlexei Starovoitov */ 12109eea9222SAlexei Starovoitov pkt_dev->last_ok = 1; 12119eea9222SAlexei Starovoitov 12129eea9222SAlexei Starovoitov /* override clone_skb if user passed default value 12139eea9222SAlexei Starovoitov * at module loading time 12149eea9222SAlexei Starovoitov */ 12159eea9222SAlexei Starovoitov pkt_dev->clone_skb = 0; 12160967f244SJohn Fastabend } else if (strcmp(f, "queue_xmit") == 0) { 12170967f244SJohn Fastabend pkt_dev->xmit_mode = M_QUEUE_XMIT; 12180967f244SJohn Fastabend pkt_dev->last_ok = 1; 121962f64aedSAlexei Starovoitov } else { 122062f64aedSAlexei Starovoitov sprintf(pg_result, 122162f64aedSAlexei Starovoitov "xmit_mode -:%s:- unknown\nAvailable modes: %s", 122262f64aedSAlexei Starovoitov f, "start_xmit, netif_receive\n"); 122362f64aedSAlexei Starovoitov return count; 122462f64aedSAlexei Starovoitov } 122562f64aedSAlexei Starovoitov sprintf(pg_result, "OK: xmit_mode=%s", f); 122662f64aedSAlexei Starovoitov return count; 122762f64aedSAlexei Starovoitov } 12281da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 12291da177e4SLinus Torvalds char f[32]; 12301da177e4SLinus Torvalds memset(f, 0, 32); 12311da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 123263adc6fbSStephen Hemminger if (len < 0) 1233222f1806SLuiz Capitulino return len; 123463adc6fbSStephen Hemminger 12351da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 12361da177e4SLinus Torvalds return -EFAULT; 12371da177e4SLinus Torvalds i += len; 12381da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 12391da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 12421da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 12431da177e4SLinus Torvalds 12441da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 12451da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 12461da177e4SLinus Torvalds 12471da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 12481da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 12511da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 12521da177e4SLinus Torvalds 12531da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 12541da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 12571da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 12601da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 12631da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 12661da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 12691da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 12721da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 12751da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 12781da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 12791da177e4SLinus Torvalds 1280ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1281ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1282ca6549afSSteven Whitehouse 1283ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1284ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1285ca6549afSSteven Whitehouse 128634954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 128734954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 128834954ddcSFrancesco Fondelli 128934954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 129034954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 129134954ddcSFrancesco Fondelli 129234954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 129334954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 129434954ddcSFrancesco Fondelli 129534954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 129634954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 129734954ddcSFrancesco Fondelli 129857a5749bSDmitry Safonov else if (strcmp(f, "FLOW_SEQ") == 0 || strcmp(f, "!FLOW_RND") == 0) 1299007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1300007a531bSJamal Hadi Salim 130157a5749bSDmitry Safonov else if (strcmp(f, "FLOW_RND") == 0 || strcmp(f, "!FLOW_SEQ") == 0) 130257a5749bSDmitry Safonov pkt_dev->flags &= ~F_FLOW_SEQ; 130357a5749bSDmitry Safonov 130445b270f8SRobert Olsson else if (strcmp(f, "QUEUE_MAP_RND") == 0) 130545b270f8SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_RND; 130645b270f8SRobert Olsson 130745b270f8SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_RND") == 0) 130845b270f8SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_RND; 1309e6fce5b9SRobert Olsson 1310e6fce5b9SRobert Olsson else if (strcmp(f, "QUEUE_MAP_CPU") == 0) 1311e6fce5b9SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_CPU; 1312e6fce5b9SRobert Olsson 1313e6fce5b9SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_CPU") == 0) 1314e6fce5b9SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_CPU; 1315a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1316a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1317*6f107c74SDmitry Safonov pkt_dev->flags |= F_IPSEC; 131857a5749bSDmitry Safonov 131957a5749bSDmitry Safonov else if (strcmp(f, "!IPSEC") == 0) 1320*6f107c74SDmitry Safonov pkt_dev->flags &= ~F_IPSEC; 1321a553e4a6SJamal Hadi Salim #endif 1322a553e4a6SJamal Hadi Salim 13231ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 13241ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 13251ca7768cSFrancesco Fondelli 1326e99b99b4SRobert Olsson else if (strcmp(f, "NODE_ALLOC") == 0) 1327e99b99b4SRobert Olsson pkt_dev->flags |= F_NODE; 1328e99b99b4SRobert Olsson 1329e99b99b4SRobert Olsson else if (strcmp(f, "!NODE_ALLOC") == 0) 1330e99b99b4SRobert Olsson pkt_dev->flags &= ~F_NODE; 1331e99b99b4SRobert Olsson 1332c26bf4a5SThomas Graf else if (strcmp(f, "UDPCSUM") == 0) 1333c26bf4a5SThomas Graf pkt_dev->flags |= F_UDPCSUM; 1334c26bf4a5SThomas Graf 1335c26bf4a5SThomas Graf else if (strcmp(f, "!UDPCSUM") == 0) 1336c26bf4a5SThomas Graf pkt_dev->flags &= ~F_UDPCSUM; 1337c26bf4a5SThomas Graf 1338afb84b62SJesper Dangaard Brouer else if (strcmp(f, "NO_TIMESTAMP") == 0) 1339afb84b62SJesper Dangaard Brouer pkt_dev->flags |= F_NO_TIMESTAMP; 1340afb84b62SJesper Dangaard Brouer 1341f1f00d8fSJesper Dangaard Brouer else if (strcmp(f, "!NO_TIMESTAMP") == 0) 1342f1f00d8fSJesper Dangaard Brouer pkt_dev->flags &= ~F_NO_TIMESTAMP; 1343f1f00d8fSJesper Dangaard Brouer 13441da177e4SLinus Torvalds else { 1345222f1806SLuiz Capitulino sprintf(pg_result, 1346222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 13471da177e4SLinus Torvalds f, 13481ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 134972f8e06fSMathias Krause "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, " 135072f8e06fSMathias Krause "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, " 135172f8e06fSMathias Krause "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, " 1352afb84b62SJesper Dangaard Brouer "NO_TIMESTAMP, " 135372f8e06fSMathias Krause #ifdef CONFIG_XFRM 135472f8e06fSMathias Krause "IPSEC, " 135572f8e06fSMathias Krause #endif 135672f8e06fSMathias Krause "NODE_ALLOC\n"); 13571da177e4SLinus Torvalds return count; 13581da177e4SLinus Torvalds } 13591da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 13601da177e4SLinus Torvalds return count; 13611da177e4SLinus Torvalds } 13621da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 13631da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 136463adc6fbSStephen Hemminger if (len < 0) 1365222f1806SLuiz Capitulino return len; 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13681da177e4SLinus Torvalds return -EFAULT; 13691da177e4SLinus Torvalds buf[len] = 0; 13701da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 13711da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 13721da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 13731da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 13741da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds if (debug) 1377f342cda7SJoe Perches pr_debug("dst_min set to: %s\n", pkt_dev->dst_min); 13781da177e4SLinus Torvalds i += len; 13791da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 13801da177e4SLinus Torvalds return count; 13811da177e4SLinus Torvalds } 13821da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 13831da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 138463adc6fbSStephen Hemminger if (len < 0) 1385222f1806SLuiz Capitulino return len; 138663adc6fbSStephen Hemminger 13871da177e4SLinus Torvalds 13881da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13891da177e4SLinus Torvalds return -EFAULT; 13901da177e4SLinus Torvalds 13911da177e4SLinus Torvalds buf[len] = 0; 13921da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 13931da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 13941da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 13951da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 13961da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 13971da177e4SLinus Torvalds } 13981da177e4SLinus Torvalds if (debug) 1399f342cda7SJoe Perches pr_debug("dst_max set to: %s\n", pkt_dev->dst_max); 14001da177e4SLinus Torvalds i += len; 14011da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 14021da177e4SLinus Torvalds return count; 14031da177e4SLinus Torvalds } 14041da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 14051da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1406222f1806SLuiz Capitulino if (len < 0) 1407222f1806SLuiz Capitulino return len; 14081da177e4SLinus Torvalds 14091da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14121da177e4SLinus Torvalds return -EFAULT; 14131da177e4SLinus Torvalds buf[len] = 0; 14141da177e4SLinus Torvalds 1415c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL); 141647a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); 14171da177e4SLinus Torvalds 14184e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr; 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds if (debug) 1421f342cda7SJoe Perches pr_debug("dst6 set to: %s\n", buf); 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds i += len; 14241da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 14251da177e4SLinus Torvalds return count; 14261da177e4SLinus Torvalds } 14271da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 14281da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1429222f1806SLuiz Capitulino if (len < 0) 1430222f1806SLuiz Capitulino return len; 14311da177e4SLinus Torvalds 14321da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14351da177e4SLinus Torvalds return -EFAULT; 14361da177e4SLinus Torvalds buf[len] = 0; 14371da177e4SLinus Torvalds 1438c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL); 143947a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); 14401da177e4SLinus Torvalds 14414e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr; 14421da177e4SLinus Torvalds if (debug) 1443f342cda7SJoe Perches pr_debug("dst6_min set to: %s\n", buf); 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds i += len; 14461da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 14471da177e4SLinus Torvalds return count; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 14501da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1451222f1806SLuiz Capitulino if (len < 0) 1452222f1806SLuiz Capitulino return len; 14531da177e4SLinus Torvalds 14541da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14571da177e4SLinus Torvalds return -EFAULT; 14581da177e4SLinus Torvalds buf[len] = 0; 14591da177e4SLinus Torvalds 1460c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL); 146147a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); 14621da177e4SLinus Torvalds 14631da177e4SLinus Torvalds if (debug) 1464f342cda7SJoe Perches pr_debug("dst6_max set to: %s\n", buf); 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds i += len; 14671da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 14681da177e4SLinus Torvalds return count; 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 14711da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1472222f1806SLuiz Capitulino if (len < 0) 1473222f1806SLuiz Capitulino return len; 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14781da177e4SLinus Torvalds return -EFAULT; 14791da177e4SLinus Torvalds buf[len] = 0; 14801da177e4SLinus Torvalds 1481c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL); 148247a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); 14831da177e4SLinus Torvalds 14844e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr; 14851da177e4SLinus Torvalds 14861da177e4SLinus Torvalds if (debug) 1487f342cda7SJoe Perches pr_debug("src6 set to: %s\n", buf); 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds i += len; 14901da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 14911da177e4SLinus Torvalds return count; 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 14941da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 149563adc6fbSStephen Hemminger if (len < 0) 1496222f1806SLuiz Capitulino return len; 149763adc6fbSStephen Hemminger 14981da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14991da177e4SLinus Torvalds return -EFAULT; 15001da177e4SLinus Torvalds buf[len] = 0; 15011da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 15021da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 15031da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 15041da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 15051da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 15061da177e4SLinus Torvalds } 15071da177e4SLinus Torvalds if (debug) 1508f342cda7SJoe Perches pr_debug("src_min set to: %s\n", pkt_dev->src_min); 15091da177e4SLinus Torvalds i += len; 15101da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 15111da177e4SLinus Torvalds return count; 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 15141da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 151563adc6fbSStephen Hemminger if (len < 0) 1516222f1806SLuiz Capitulino return len; 151763adc6fbSStephen Hemminger 15181da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 15191da177e4SLinus Torvalds return -EFAULT; 15201da177e4SLinus Torvalds buf[len] = 0; 15211da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 15221da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 15231da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 15241da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 15251da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds if (debug) 1528f342cda7SJoe Perches pr_debug("src_max set to: %s\n", pkt_dev->src_max); 15291da177e4SLinus Torvalds i += len; 15301da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 15311da177e4SLinus Torvalds return count; 15321da177e4SLinus Torvalds } 15331da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 15341da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 153563adc6fbSStephen Hemminger if (len < 0) 1536222f1806SLuiz Capitulino return len; 153763adc6fbSStephen Hemminger 15381da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 15391da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 15401da177e4SLinus Torvalds return -EFAULT; 15411da177e4SLinus Torvalds 15424940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->dst_mac)) 15434940fc88SAlexey Dobriyan return -EINVAL; 15441da177e4SLinus Torvalds /* Set up Dest MAC */ 15459ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); 15461da177e4SLinus Torvalds 15474940fc88SAlexey Dobriyan sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); 15481da177e4SLinus Torvalds return count; 15491da177e4SLinus Torvalds } 15501da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 15511da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 155263adc6fbSStephen Hemminger if (len < 0) 1553222f1806SLuiz Capitulino return len; 155463adc6fbSStephen Hemminger 15551da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 15561da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 15571da177e4SLinus Torvalds return -EFAULT; 15581da177e4SLinus Torvalds 15594940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->src_mac)) 15604940fc88SAlexey Dobriyan return -EINVAL; 1561ce5d0b47SAdit Ranadive /* Set up Src MAC */ 15629ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); 1563ce5d0b47SAdit Ranadive 15644940fc88SAlexey Dobriyan sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); 15651da177e4SLinus Torvalds return count; 15661da177e4SLinus Torvalds } 15671da177e4SLinus Torvalds 15681da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 15691da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 15701da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 15711da177e4SLinus Torvalds return count; 15721da177e4SLinus Torvalds } 15731da177e4SLinus Torvalds 15741da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 15751da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 157663adc6fbSStephen Hemminger if (len < 0) 1577222f1806SLuiz Capitulino return len; 157863adc6fbSStephen Hemminger 15791da177e4SLinus Torvalds i += len; 15801da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15811da177e4SLinus Torvalds value = MAX_CFLOWS; 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds pkt_dev->cflows = value; 15841da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15851da177e4SLinus Torvalds return count; 15861da177e4SLinus Torvalds } 15876bae9190SFan Du #ifdef CONFIG_XFRM 1588de4aee7dSFan Du if (!strcmp(name, "spi")) { 1589de4aee7dSFan Du len = num_arg(&user_buffer[i], 10, &value); 1590de4aee7dSFan Du if (len < 0) 1591de4aee7dSFan Du return len; 1592de4aee7dSFan Du 1593de4aee7dSFan Du i += len; 1594de4aee7dSFan Du pkt_dev->spi = value; 1595de4aee7dSFan Du sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); 1596de4aee7dSFan Du return count; 1597de4aee7dSFan Du } 15986bae9190SFan Du #endif 15991da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 16001da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 160163adc6fbSStephen Hemminger if (len < 0) 1602222f1806SLuiz Capitulino return len; 160363adc6fbSStephen Hemminger 16041da177e4SLinus Torvalds i += len; 16051da177e4SLinus Torvalds pkt_dev->lflow = value; 16061da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 16071da177e4SLinus Torvalds return count; 16081da177e4SLinus Torvalds } 16091da177e4SLinus Torvalds 161045b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 161145b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 161263adc6fbSStephen Hemminger if (len < 0) 161345b270f8SRobert Olsson return len; 161463adc6fbSStephen Hemminger 161545b270f8SRobert Olsson i += len; 161645b270f8SRobert Olsson pkt_dev->queue_map_min = value; 161745b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 161845b270f8SRobert Olsson return count; 161945b270f8SRobert Olsson } 162045b270f8SRobert Olsson 162145b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 162245b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 162363adc6fbSStephen Hemminger if (len < 0) 162445b270f8SRobert Olsson return len; 162563adc6fbSStephen Hemminger 162645b270f8SRobert Olsson i += len; 162745b270f8SRobert Olsson pkt_dev->queue_map_max = value; 162845b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 162945b270f8SRobert Olsson return count; 163045b270f8SRobert Olsson } 163145b270f8SRobert Olsson 1632ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 163395c96174SEric Dumazet unsigned int n, cnt; 1634cfcabdccSStephen Hemminger 1635ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1636cfcabdccSStephen Hemminger if (len < 0) 1637cfcabdccSStephen Hemminger return len; 1638ca6549afSSteven Whitehouse i += len; 1639cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1640ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1641cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1642ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1643ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 164434954ddcSFrancesco Fondelli 164534954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 164634954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 164734954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 164834954ddcSFrancesco Fondelli 164934954ddcSFrancesco Fondelli if (debug) 1650f342cda7SJoe Perches pr_debug("VLAN/SVLAN auto turned off\n"); 165134954ddcSFrancesco Fondelli } 165234954ddcSFrancesco Fondelli return count; 165334954ddcSFrancesco Fondelli } 165434954ddcSFrancesco Fondelli 165534954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 165634954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 165763adc6fbSStephen Hemminger if (len < 0) 165834954ddcSFrancesco Fondelli return len; 165963adc6fbSStephen Hemminger 166034954ddcSFrancesco Fondelli i += len; 166134954ddcSFrancesco Fondelli if (value <= 4095) { 166234954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 166334954ddcSFrancesco Fondelli 166434954ddcSFrancesco Fondelli if (debug) 1665f342cda7SJoe Perches pr_debug("VLAN turned on\n"); 166634954ddcSFrancesco Fondelli 166734954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1668f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 166934954ddcSFrancesco Fondelli 167034954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 167134954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 167234954ddcSFrancesco Fondelli } else { 167334954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 167434954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 167534954ddcSFrancesco Fondelli 167634954ddcSFrancesco Fondelli if (debug) 1677f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 167834954ddcSFrancesco Fondelli } 167934954ddcSFrancesco Fondelli return count; 168034954ddcSFrancesco Fondelli } 168134954ddcSFrancesco Fondelli 168234954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 168334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 168463adc6fbSStephen Hemminger if (len < 0) 168534954ddcSFrancesco Fondelli return len; 168663adc6fbSStephen Hemminger 168734954ddcSFrancesco Fondelli i += len; 168834954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 168934954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 169034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 169134954ddcSFrancesco Fondelli } else { 169234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 169334954ddcSFrancesco Fondelli } 169434954ddcSFrancesco Fondelli return count; 169534954ddcSFrancesco Fondelli } 169634954ddcSFrancesco Fondelli 169734954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 169834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 169963adc6fbSStephen Hemminger if (len < 0) 170034954ddcSFrancesco Fondelli return len; 170163adc6fbSStephen Hemminger 170234954ddcSFrancesco Fondelli i += len; 170334954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 170434954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 170534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 170634954ddcSFrancesco Fondelli } else { 170734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 170834954ddcSFrancesco Fondelli } 170934954ddcSFrancesco Fondelli return count; 171034954ddcSFrancesco Fondelli } 171134954ddcSFrancesco Fondelli 171234954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 171334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 171463adc6fbSStephen Hemminger if (len < 0) 171534954ddcSFrancesco Fondelli return len; 171663adc6fbSStephen Hemminger 171734954ddcSFrancesco Fondelli i += len; 171834954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 171934954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 172034954ddcSFrancesco Fondelli 172134954ddcSFrancesco Fondelli if (debug) 1722f342cda7SJoe Perches pr_debug("SVLAN turned on\n"); 172334954ddcSFrancesco Fondelli 172434954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1725f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 172634954ddcSFrancesco Fondelli 172734954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 172834954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 172934954ddcSFrancesco Fondelli } else { 173034954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 173134954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 173234954ddcSFrancesco Fondelli 173334954ddcSFrancesco Fondelli if (debug) 1734f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 173534954ddcSFrancesco Fondelli } 173634954ddcSFrancesco Fondelli return count; 173734954ddcSFrancesco Fondelli } 173834954ddcSFrancesco Fondelli 173934954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 174034954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 174163adc6fbSStephen Hemminger if (len < 0) 174234954ddcSFrancesco Fondelli return len; 174363adc6fbSStephen Hemminger 174434954ddcSFrancesco Fondelli i += len; 174534954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 174634954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 174734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 174834954ddcSFrancesco Fondelli } else { 174934954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 175034954ddcSFrancesco Fondelli } 175134954ddcSFrancesco Fondelli return count; 175234954ddcSFrancesco Fondelli } 175334954ddcSFrancesco Fondelli 175434954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 175534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 175663adc6fbSStephen Hemminger if (len < 0) 175734954ddcSFrancesco Fondelli return len; 175863adc6fbSStephen Hemminger 175934954ddcSFrancesco Fondelli i += len; 176034954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 176134954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 176234954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 176334954ddcSFrancesco Fondelli } else { 176434954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 176534954ddcSFrancesco Fondelli } 1766ca6549afSSteven Whitehouse return count; 1767ca6549afSSteven Whitehouse } 1768ca6549afSSteven Whitehouse 17691ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 17701ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17711ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 177263adc6fbSStephen Hemminger if (len < 0) 17731ca7768cSFrancesco Fondelli return len; 177463adc6fbSStephen Hemminger 17751ca7768cSFrancesco Fondelli i += len; 17761ca7768cSFrancesco Fondelli if (len == 2) { 17771ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 17781ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 17791ca7768cSFrancesco Fondelli } else { 17801ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 17811ca7768cSFrancesco Fondelli } 17821ca7768cSFrancesco Fondelli return count; 17831ca7768cSFrancesco Fondelli } 17841ca7768cSFrancesco Fondelli 17851ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 17861ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17871ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 178863adc6fbSStephen Hemminger if (len < 0) 17891ca7768cSFrancesco Fondelli return len; 179063adc6fbSStephen Hemminger 17911ca7768cSFrancesco Fondelli i += len; 17921ca7768cSFrancesco Fondelli if (len == 2) { 17931ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17941ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17951ca7768cSFrancesco Fondelli } else { 17961ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17971ca7768cSFrancesco Fondelli } 17981ca7768cSFrancesco Fondelli return count; 17991ca7768cSFrancesco Fondelli } 18001ca7768cSFrancesco Fondelli 18019e50e3acSJohn Fastabend if (!strcmp(name, "skb_priority")) { 18029e50e3acSJohn Fastabend len = num_arg(&user_buffer[i], 9, &value); 18039e50e3acSJohn Fastabend if (len < 0) 18049e50e3acSJohn Fastabend return len; 18059e50e3acSJohn Fastabend 18069e50e3acSJohn Fastabend i += len; 18079e50e3acSJohn Fastabend pkt_dev->skb_priority = value; 18089e50e3acSJohn Fastabend sprintf(pg_result, "OK: skb_priority=%i", 18099e50e3acSJohn Fastabend pkt_dev->skb_priority); 18109e50e3acSJohn Fastabend return count; 18119e50e3acSJohn Fastabend } 18129e50e3acSJohn Fastabend 18131da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 18141da177e4SLinus Torvalds return -EINVAL; 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds 1817d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 18181da177e4SLinus Torvalds { 1819d9dda78bSAl Viro return single_open(file, pktgen_if_show, PDE_DATA(inode)); 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds 18229a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1823d50a6b56SStephen Hemminger .open = pktgen_if_open, 1824d50a6b56SStephen Hemminger .read = seq_read, 1825d50a6b56SStephen Hemminger .llseek = seq_lseek, 1826d50a6b56SStephen Hemminger .write = pktgen_if_write, 1827d50a6b56SStephen Hemminger .release = single_release, 1828d50a6b56SStephen Hemminger }; 1829d50a6b56SStephen Hemminger 1830d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1831d50a6b56SStephen Hemminger { 1832d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1833648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1834d50a6b56SStephen Hemminger 1835d50a6b56SStephen Hemminger BUG_ON(!t); 1836d50a6b56SStephen Hemminger 183797dc48e2SThomas Graf seq_puts(seq, "Running: "); 18381da177e4SLinus Torvalds 18398788370aSJesper Dangaard Brouer rcu_read_lock(); 18408788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 18411da177e4SLinus Torvalds if (pkt_dev->running) 1842593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 18431da177e4SLinus Torvalds 184497dc48e2SThomas Graf seq_puts(seq, "\nStopped: "); 18451da177e4SLinus Torvalds 18468788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 18471da177e4SLinus Torvalds if (!pkt_dev->running) 1848593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds if (t->result[0]) 1851d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 18521da177e4SLinus Torvalds else 185397dc48e2SThomas Graf seq_puts(seq, "\nResult: NA\n"); 18541da177e4SLinus Torvalds 18558788370aSJesper Dangaard Brouer rcu_read_unlock(); 18561da177e4SLinus Torvalds 1857d50a6b56SStephen Hemminger return 0; 18581da177e4SLinus Torvalds } 18591da177e4SLinus Torvalds 1860d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1861d50a6b56SStephen Hemminger const char __user * user_buffer, 1862d50a6b56SStephen Hemminger size_t count, loff_t * offset) 18631da177e4SLinus Torvalds { 18648a994a71SJoe Perches struct seq_file *seq = file->private_data; 1865d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1866d6182223SPaul Gortmaker int i, max, len, ret; 18671da177e4SLinus Torvalds char name[40]; 18681da177e4SLinus Torvalds char *pg_result; 18691da177e4SLinus Torvalds 18701da177e4SLinus Torvalds if (count < 1) { 18711da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 18721da177e4SLinus Torvalds return -EINVAL; 18731da177e4SLinus Torvalds } 18741da177e4SLinus Torvalds 1875d6182223SPaul Gortmaker max = count; 1876d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 18771da177e4SLinus Torvalds if (len < 0) 18781da177e4SLinus Torvalds return len; 18791da177e4SLinus Torvalds 1880d6182223SPaul Gortmaker i = len; 18811da177e4SLinus Torvalds 18821da177e4SLinus Torvalds /* Read variable name */ 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 18851da177e4SLinus Torvalds if (len < 0) 18861da177e4SLinus Torvalds return len; 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 18891da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 18901da177e4SLinus Torvalds return -EFAULT; 18911da177e4SLinus Torvalds i += len; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds max = count - i; 18941da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 18951da177e4SLinus Torvalds if (len < 0) 18961da177e4SLinus Torvalds return len; 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds i += len; 18991da177e4SLinus Torvalds 19001da177e4SLinus Torvalds if (debug) 1901f342cda7SJoe Perches pr_debug("t=%s, count=%lu\n", name, (unsigned long)count); 19021da177e4SLinus Torvalds 19031da177e4SLinus Torvalds if (!t) { 1904f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 19051da177e4SLinus Torvalds ret = -EINVAL; 19061da177e4SLinus Torvalds goto out; 19071da177e4SLinus Torvalds } 19081da177e4SLinus Torvalds 19091da177e4SLinus Torvalds pg_result = &(t->result[0]); 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 19121da177e4SLinus Torvalds char f[32]; 19131da177e4SLinus Torvalds memset(f, 0, 32); 19141da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 19151da177e4SLinus Torvalds if (len < 0) { 19161da177e4SLinus Torvalds ret = len; 19171da177e4SLinus Torvalds goto out; 19181da177e4SLinus Torvalds } 19191da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 19201da177e4SLinus Torvalds return -EFAULT; 19211da177e4SLinus Torvalds i += len; 19226146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1923604dfd6eSCong Wang ret = pktgen_add_device(t, f); 19246146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1925604dfd6eSCong Wang if (!ret) { 19261da177e4SLinus Torvalds ret = count; 19271da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 1928604dfd6eSCong Wang } else 1929604dfd6eSCong Wang sprintf(pg_result, "ERROR: can not add device %s", f); 19301da177e4SLinus Torvalds goto out; 19311da177e4SLinus Torvalds } 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 19346146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 193595ed63f7SArthur Kepner t->control |= T_REMDEVALL; 19366146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1937121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 19381da177e4SLinus Torvalds ret = count; 19391da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 19401da177e4SLinus Torvalds goto out; 19411da177e4SLinus Torvalds } 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1944b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 19451da177e4SLinus Torvalds ret = count; 19461da177e4SLinus Torvalds goto out; 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds ret = -EINVAL; 19501da177e4SLinus Torvalds out: 19511da177e4SLinus Torvalds return ret; 19521da177e4SLinus Torvalds } 19531da177e4SLinus Torvalds 1954d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 19551da177e4SLinus Torvalds { 1956d9dda78bSAl Viro return single_open(file, pktgen_thread_show, PDE_DATA(inode)); 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds 19599a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1960d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1961d50a6b56SStephen Hemminger .read = seq_read, 1962d50a6b56SStephen Hemminger .llseek = seq_lseek, 1963d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1964d50a6b56SStephen Hemminger .release = single_release, 1965d50a6b56SStephen Hemminger }; 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds /* Think find or remove for NN */ 19684e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, 19694e58a027SCong Wang const char *ifname, int remove) 19701da177e4SLinus Torvalds { 19711da177e4SLinus Torvalds struct pktgen_thread *t; 19721da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 19733e984840SEric Dumazet bool exact = (remove == FIND); 19741da177e4SLinus Torvalds 19754e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 19763e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 19771da177e4SLinus Torvalds if (pkt_dev) { 19781da177e4SLinus Torvalds if (remove) { 197995ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 198095ed63f7SArthur Kepner t->control |= T_REMDEV; 19811da177e4SLinus Torvalds } 19821da177e4SLinus Torvalds break; 19831da177e4SLinus Torvalds } 19841da177e4SLinus Torvalds } 19851da177e4SLinus Torvalds return pkt_dev; 19861da177e4SLinus Torvalds } 19871da177e4SLinus Torvalds 198895ed63f7SArthur Kepner /* 198995ed63f7SArthur Kepner * mark a device for removal 199095ed63f7SArthur Kepner */ 19914e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname) 19921da177e4SLinus Torvalds { 19931da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 199495ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 199595ed63f7SArthur Kepner int i = 0; 199695ed63f7SArthur Kepner 19976146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1998f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 199995ed63f7SArthur Kepner 200095ed63f7SArthur Kepner while (1) { 200195ed63f7SArthur Kepner 20024e58a027SCong Wang pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE); 2003222f1806SLuiz Capitulino if (pkt_dev == NULL) 2004222f1806SLuiz Capitulino break; /* success */ 200595ed63f7SArthur Kepner 20066146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 2007f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 2008f9467eaeSJoe Perches __func__, ifname); 200995ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 20106146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 201195ed63f7SArthur Kepner 201295ed63f7SArthur Kepner if (++i >= max_tries) { 2013f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 2014f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 201595ed63f7SArthur Kepner break; 201695ed63f7SArthur Kepner } 201795ed63f7SArthur Kepner 201895ed63f7SArthur Kepner } 201995ed63f7SArthur Kepner 20206146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 202139df232fSStephen Hemminger } 202295ed63f7SArthur Kepner 20234e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) 202439df232fSStephen Hemminger { 202539df232fSStephen Hemminger struct pktgen_thread *t; 202639df232fSStephen Hemminger 20279a0b1e8bSEric Dumazet mutex_lock(&pktgen_thread_lock); 20289a0b1e8bSEric Dumazet 20294e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 203039df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 203139df232fSStephen Hemminger 20329a0b1e8bSEric Dumazet if_lock(t); 20339a0b1e8bSEric Dumazet list_for_each_entry(pkt_dev, &t->if_list, list) { 203439df232fSStephen Hemminger if (pkt_dev->odev != dev) 203539df232fSStephen Hemminger continue; 203639df232fSStephen Hemminger 2037a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 203839df232fSStephen Hemminger 20392975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 20404e58a027SCong Wang pn->proc_dir, 20412975315bSAlexey Dobriyan &pktgen_if_fops, 20422975315bSAlexey Dobriyan pkt_dev); 204339df232fSStephen Hemminger if (!pkt_dev->entry) 2044f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 2045f9467eaeSJoe Perches dev->name); 204639df232fSStephen Hemminger break; 204739df232fSStephen Hemminger } 20489a0b1e8bSEric Dumazet if_unlock(t); 204939df232fSStephen Hemminger } 20509a0b1e8bSEric Dumazet mutex_unlock(&pktgen_thread_lock); 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds 2053222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 2054222f1806SLuiz Capitulino unsigned long event, void *ptr) 20551da177e4SLinus Torvalds { 2056351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 20574e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id); 20581da177e4SLinus Torvalds 20594e58a027SCong Wang if (pn->pktgen_exiting) 2060e9dc8653SEric W. Biederman return NOTIFY_DONE; 2061e9dc8653SEric W. Biederman 20621da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 20631da177e4SLinus Torvalds * as we run under the RTNL lock. 20641da177e4SLinus Torvalds */ 20651da177e4SLinus Torvalds 20661da177e4SLinus Torvalds switch (event) { 206739df232fSStephen Hemminger case NETDEV_CHANGENAME: 20684e58a027SCong Wang pktgen_change_name(pn, dev); 20691da177e4SLinus Torvalds break; 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds case NETDEV_UNREGISTER: 20724e58a027SCong Wang pktgen_mark_device(pn, dev->name); 20731da177e4SLinus Torvalds break; 20743ff50b79SStephen Hemminger } 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds return NOTIFY_DONE; 20771da177e4SLinus Torvalds } 20781da177e4SLinus Torvalds 20794e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn, 20804e58a027SCong Wang struct pktgen_dev *pkt_dev, 208163adc6fbSStephen Hemminger const char *ifname) 2082e6fce5b9SRobert Olsson { 2083e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 2084d6182223SPaul Gortmaker int i; 2085e6fce5b9SRobert Olsson 2086e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 2087e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 2088e6fce5b9SRobert Olsson break; 2089e6fce5b9SRobert Olsson 2090e6fce5b9SRobert Olsson b[i] = ifname[i]; 2091e6fce5b9SRobert Olsson } 2092e6fce5b9SRobert Olsson b[i] = 0; 2093e6fce5b9SRobert Olsson 20944e58a027SCong Wang return dev_get_by_name(pn->net, b); 2095e6fce5b9SRobert Olsson } 2096e6fce5b9SRobert Olsson 2097e6fce5b9SRobert Olsson 20981da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 20991da177e4SLinus Torvalds 21004e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn, 21014e58a027SCong Wang struct pktgen_dev *pkt_dev, const char *ifname) 2102222f1806SLuiz Capitulino { 21031da177e4SLinus Torvalds struct net_device *odev; 210439df232fSStephen Hemminger int err; 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds /* Clean old setups */ 21071da177e4SLinus Torvalds if (pkt_dev->odev) { 21081da177e4SLinus Torvalds dev_put(pkt_dev->odev); 21091da177e4SLinus Torvalds pkt_dev->odev = NULL; 21101da177e4SLinus Torvalds } 21111da177e4SLinus Torvalds 21124e58a027SCong Wang odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname); 21131da177e4SLinus Torvalds if (!odev) { 2114f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 211539df232fSStephen Hemminger return -ENODEV; 21161da177e4SLinus Torvalds } 211739df232fSStephen Hemminger 21181da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 2119f9467eaeSJoe Perches pr_err("not an ethernet device: \"%s\"\n", ifname); 212039df232fSStephen Hemminger err = -EINVAL; 212139df232fSStephen Hemminger } else if (!netif_running(odev)) { 2122f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 212339df232fSStephen Hemminger err = -ENETDOWN; 212439df232fSStephen Hemminger } else { 21251da177e4SLinus Torvalds pkt_dev->odev = odev; 212639df232fSStephen Hemminger return 0; 212739df232fSStephen Hemminger } 21281da177e4SLinus Torvalds 21291da177e4SLinus Torvalds dev_put(odev); 213039df232fSStephen Hemminger return err; 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds 21331da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 21341da177e4SLinus Torvalds * structure to have the right information to create/send packets 21351da177e4SLinus Torvalds */ 21361da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 21371da177e4SLinus Torvalds { 213864c00d81SAndrew Gallatin int ntxq; 213964c00d81SAndrew Gallatin 21401da177e4SLinus Torvalds if (!pkt_dev->odev) { 2141f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2142222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2143222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 21441da177e4SLinus Torvalds return; 21451da177e4SLinus Torvalds } 21461da177e4SLinus Torvalds 214764c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 214864c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2149bfdbc0acSRobert Olsson 215064c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2151294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 215288271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2153593f63b0SEric Dumazet pkt_dev->odevname); 215426e29eedSDan Carpenter pkt_dev->queue_map_min = (ntxq ?: 1) - 1; 215564c00d81SAndrew Gallatin } 215688271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2157294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 215888271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2159593f63b0SEric Dumazet pkt_dev->odevname); 216026e29eedSDan Carpenter pkt_dev->queue_map_max = (ntxq ?: 1) - 1; 216164c00d81SAndrew Gallatin } 216264c00d81SAndrew Gallatin 21631da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 21641da177e4SLinus Torvalds 2165f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 21669ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds /* Set up Dest MAC */ 21699ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 21724c139b8cSAmerigo Wang int i, set = 0, err = 1; 21734c139b8cSAmerigo Wang struct inet6_dev *idev; 21744c139b8cSAmerigo Wang 217568bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 217668bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr) 217768bf9f0bSAmerigo Wang + sizeof(struct udphdr) 217868bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 217968bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 218068bf9f0bSAmerigo Wang } 218168bf9f0bSAmerigo Wang 2182df7e8e2eSEric Dumazet for (i = 0; i < sizeof(struct in6_addr); i++) 21831da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 21841da177e4SLinus Torvalds set = 1; 21851da177e4SLinus Torvalds break; 21861da177e4SLinus Torvalds } 21871da177e4SLinus Torvalds 21881da177e4SLinus Torvalds if (!set) { 21891da177e4SLinus Torvalds 21901da177e4SLinus Torvalds /* 21911da177e4SLinus Torvalds * Use linklevel address if unconfigured. 21921da177e4SLinus Torvalds * 21931da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 21941da177e4SLinus Torvalds */ 21951da177e4SLinus Torvalds 21968814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 219763adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 219863adc6fbSStephen Hemminger if (idev) { 21991da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds read_lock_bh(&idev->lock); 22024c139b8cSAmerigo Wang list_for_each_entry(ifp, &idev->addr_list, if_list) { 22034c139b8cSAmerigo Wang if ((ifp->scope & IFA_LINK) && 2204f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 22054e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = ifp->addr; 22061da177e4SLinus Torvalds err = 0; 22071da177e4SLinus Torvalds break; 22081da177e4SLinus Torvalds } 22091da177e4SLinus Torvalds } 22101da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 22111da177e4SLinus Torvalds } 22128814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2213222f1806SLuiz Capitulino if (err) 2214f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 22151da177e4SLinus Torvalds } 2216222f1806SLuiz Capitulino } else { 221768bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 221868bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr) 221968bf9f0bSAmerigo Wang + sizeof(struct udphdr) 222068bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 222168bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 222268bf9f0bSAmerigo Wang } 222368bf9f0bSAmerigo Wang 22241da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 22251da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 22261da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 22271da177e4SLinus Torvalds 22281da177e4SLinus Torvalds struct in_device *in_dev; 22291da177e4SLinus Torvalds 22301da177e4SLinus Torvalds rcu_read_lock(); 2231e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 22321da177e4SLinus Torvalds if (in_dev) { 22331da177e4SLinus Torvalds if (in_dev->ifa_list) { 2234222f1806SLuiz Capitulino pkt_dev->saddr_min = 2235222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 22361da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 22371da177e4SLinus Torvalds } 22381da177e4SLinus Torvalds } 22391da177e4SLinus Torvalds rcu_read_unlock(); 2240222f1806SLuiz Capitulino } else { 22411da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 22421da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 22431da177e4SLinus Torvalds } 22441da177e4SLinus Torvalds 22451da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 22461da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds /* Initialize current values. */ 224968bf9f0bSAmerigo Wang pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 225068bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size) 225168bf9f0bSAmerigo Wang pkt_dev->max_pkt_size = pkt_dev->min_pkt_size; 225268bf9f0bSAmerigo Wang 22531da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 22541da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 22551da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 22561da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 22571da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 22581da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 22591da177e4SLinus Torvalds pkt_dev->nflows = 0; 22601da177e4SLinus Torvalds } 22611da177e4SLinus Torvalds 22621da177e4SLinus Torvalds 2263fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2264fd29cf72SStephen Hemminger { 2265ef87979cSStephen Hemminger ktime_t start_time, end_time; 2266417bc4b8SEric Dumazet s64 remaining; 22672bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2268fd29cf72SStephen Hemminger 22692bc481cfSStephen Hemminger hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 22702bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2271fd29cf72SStephen Hemminger 227243d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2273bcf91bdbSGuenter Roeck if (remaining <= 0) 2274bcf91bdbSGuenter Roeck goto out; 22752bc481cfSStephen Hemminger 2276398f382cSDaniel Borkmann start_time = ktime_get(); 227733136d12SEric Dumazet if (remaining < 100000) { 227833136d12SEric Dumazet /* for small delays (<100us), just loop until limit is reached */ 227933136d12SEric Dumazet do { 2280398f382cSDaniel Borkmann end_time = ktime_get(); 2281398f382cSDaniel Borkmann } while (ktime_compare(end_time, spin_until) < 0); 228233136d12SEric Dumazet } else { 22832bc481cfSStephen Hemminger /* see do_nanosleep */ 22842bc481cfSStephen Hemminger hrtimer_init_sleeper(&t, current); 22852bc481cfSStephen Hemminger do { 22862bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 22872bc481cfSStephen Hemminger hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); 22882bc481cfSStephen Hemminger 22892bc481cfSStephen Hemminger if (likely(t.task)) 22901da177e4SLinus Torvalds schedule(); 22911da177e4SLinus Torvalds 22922bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 22932bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 22942bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 2295398f382cSDaniel Borkmann end_time = ktime_get(); 229633136d12SEric Dumazet } 2297ef87979cSStephen Hemminger 2298ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 2299bcf91bdbSGuenter Roeck out: 230007a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 2301bcf91bdbSGuenter Roeck destroy_hrtimer_on_stack(&t.timer); 23021da177e4SLinus Torvalds } 23031da177e4SLinus Torvalds 230416dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 230516dab72fSJamal Hadi Salim { 230663d75463SPaolo Abeni pkt_dev->pkt_overhead = 0; 230716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 230816dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 230916dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 231016dab72fSJamal Hadi Salim } 231116dab72fSJamal Hadi Salim 2312648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2313007a531bSJamal Hadi Salim { 2314648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2315007a531bSJamal Hadi Salim } 2316007a531bSJamal Hadi Salim 2317007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2318007a531bSJamal Hadi Salim { 2319007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2320007a531bSJamal Hadi Salim 2321007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2322007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2323007a531bSJamal Hadi Salim /* reset time */ 2324007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 23251211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2326007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2327007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2328007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2329007a531bSJamal Hadi Salim } 2330007a531bSJamal Hadi Salim } else { 233133d7c5e5SAkinobu Mita flow = prandom_u32() % pkt_dev->cflows; 23321211a645SRobert Olsson pkt_dev->curfl = flow; 2333007a531bSJamal Hadi Salim 23341211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2335007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 23361211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 23371211a645SRobert Olsson } 2338007a531bSJamal Hadi Salim } 2339007a531bSJamal Hadi Salim 2340007a531bSJamal Hadi Salim return pkt_dev->curfl; 2341007a531bSJamal Hadi Salim } 2342007a531bSJamal Hadi Salim 2343a553e4a6SJamal Hadi Salim 2344a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2345a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2346a553e4a6SJamal Hadi Salim * we go look for it ... 2347a553e4a6SJamal Hadi Salim */ 2348bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2349fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2350a553e4a6SJamal Hadi Salim { 2351a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 23524e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); 2353a553e4a6SJamal Hadi Salim if (!x) { 2354c454997eSFan Du 2355c454997eSFan Du if (pkt_dev->spi) { 2356c454997eSFan Du /* We need as quick as possible to find the right SA 2357c454997eSFan Du * Searching with minimum criteria to archieve this. 2358c454997eSFan Du */ 2359c454997eSFan Du x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); 2360c454997eSFan Du } else { 2361a553e4a6SJamal Hadi Salim /* slow path: we dont already have xfrm_state */ 23624e58a027SCong Wang x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 23635447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2364a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2365a553e4a6SJamal Hadi Salim AF_INET, 2366a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2367a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2368c454997eSFan Du } 2369a553e4a6SJamal Hadi Salim if (x) { 2370a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2371a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2372a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2373a553e4a6SJamal Hadi Salim } 2374a553e4a6SJamal Hadi Salim 2375a553e4a6SJamal Hadi Salim } 2376a553e4a6SJamal Hadi Salim } 2377a553e4a6SJamal Hadi Salim #endif 2378fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2379fd2ea0a7SDavid S. Miller { 2380e6fce5b9SRobert Olsson 2381e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2382e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2383e6fce5b9SRobert Olsson 2384896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2385fd2ea0a7SDavid S. Miller __u16 t; 2386fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 238733d7c5e5SAkinobu Mita t = prandom_u32() % 2388fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2389fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2390fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2391fd2ea0a7SDavid S. Miller } else { 2392fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2393fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2394fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2395fd2ea0a7SDavid S. Miller } 2396fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2397fd2ea0a7SDavid S. Miller } 2398bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2399fd2ea0a7SDavid S. Miller } 2400fd2ea0a7SDavid S. Miller 24011da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 24021da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 24031da177e4SLinus Torvalds */ 2404222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2405222f1806SLuiz Capitulino { 24061da177e4SLinus Torvalds __u32 imn; 24071da177e4SLinus Torvalds __u32 imx; 24081da177e4SLinus Torvalds int flow = 0; 24091da177e4SLinus Torvalds 2410007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2411007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 24121da177e4SLinus Torvalds 24131da177e4SLinus Torvalds /* Deal with source MAC */ 24141da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 24151da177e4SLinus Torvalds __u32 mc; 24161da177e4SLinus Torvalds __u32 tmp; 24171da177e4SLinus Torvalds 24181da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 241933d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->src_mac_count; 24201da177e4SLinus Torvalds else { 24211da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2422ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2423222f1806SLuiz Capitulino pkt_dev->src_mac_count) 24241da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 24251da177e4SLinus Torvalds } 24261da177e4SLinus Torvalds 24271da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 24281da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 24291da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 24301da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 24311da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 24321da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 24331da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 24341da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 24351da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 24361da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 24371da177e4SLinus Torvalds } 24381da177e4SLinus Torvalds 24391da177e4SLinus Torvalds /* Deal with Destination MAC */ 24401da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 24411da177e4SLinus Torvalds __u32 mc; 24421da177e4SLinus Torvalds __u32 tmp; 24431da177e4SLinus Torvalds 24441da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 244533d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->dst_mac_count; 24461da177e4SLinus Torvalds 24471da177e4SLinus Torvalds else { 24481da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2449ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2450222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 24511da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 24521da177e4SLinus Torvalds } 24531da177e4SLinus Torvalds } 24541da177e4SLinus Torvalds 24551da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 24561da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 24571da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 24581da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 24591da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 24601da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 24611da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 24621da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 24631da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 24641da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds 2467ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 246895c96174SEric Dumazet unsigned int i; 2469ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2470ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2471ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 247233d7c5e5SAkinobu Mita ((__force __be32)prandom_u32() & 2473ca6549afSSteven Whitehouse htonl(0x000fffff)); 2474ca6549afSSteven Whitehouse } 2475ca6549afSSteven Whitehouse 247634954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 247733d7c5e5SAkinobu Mita pkt_dev->vlan_id = prandom_u32() & (4096 - 1); 247834954ddcSFrancesco Fondelli } 247934954ddcSFrancesco Fondelli 248034954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 248133d7c5e5SAkinobu Mita pkt_dev->svlan_id = prandom_u32() & (4096 - 1); 248234954ddcSFrancesco Fondelli } 248334954ddcSFrancesco Fondelli 24841da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 24851da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 248633d7c5e5SAkinobu Mita pkt_dev->cur_udp_src = prandom_u32() % 24875fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 24885fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 24891da177e4SLinus Torvalds 24901da177e4SLinus Torvalds else { 24911da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 24921da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 24931da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 24941da177e4SLinus Torvalds } 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds 24971da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 24981da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 249933d7c5e5SAkinobu Mita pkt_dev->cur_udp_dst = prandom_u32() % 25005fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 25015fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2502222f1806SLuiz Capitulino } else { 25031da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 25041da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 25051da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 25061da177e4SLinus Torvalds } 25071da177e4SLinus Torvalds } 25081da177e4SLinus Torvalds 25091da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 25101da177e4SLinus Torvalds 251163adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 251263adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 251363adc6fbSStephen Hemminger if (imn < imx) { 25141da177e4SLinus Torvalds __u32 t; 25151da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 251633d7c5e5SAkinobu Mita t = prandom_u32() % (imx - imn) + imn; 25171da177e4SLinus Torvalds else { 25181da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 25191da177e4SLinus Torvalds t++; 252063adc6fbSStephen Hemminger if (t > imx) 25211da177e4SLinus Torvalds t = imn; 252263adc6fbSStephen Hemminger 25231da177e4SLinus Torvalds } 25241da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 25251da177e4SLinus Torvalds } 25261da177e4SLinus Torvalds 2527007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 25281da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 25291da177e4SLinus Torvalds } else { 2530252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2531252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2532252e3346SAl Viro if (imn < imx) { 25331da177e4SLinus Torvalds __u32 t; 2534252e3346SAl Viro __be32 s; 25351da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 25361da177e4SLinus Torvalds 253770e3ba72SAkinobu Mita do { 253833d7c5e5SAkinobu Mita t = prandom_u32() % 253933d7c5e5SAkinobu Mita (imx - imn) + imn; 2540252e3346SAl Viro s = htonl(t); 254170e3ba72SAkinobu Mita } while (ipv4_is_loopback(s) || 254270e3ba72SAkinobu Mita ipv4_is_multicast(s) || 254370e3ba72SAkinobu Mita ipv4_is_lbcast(s) || 254470e3ba72SAkinobu Mita ipv4_is_zeronet(s) || 254570e3ba72SAkinobu Mita ipv4_is_local_multicast(s)); 2546252e3346SAl Viro pkt_dev->cur_daddr = s; 2547252e3346SAl Viro } else { 25481da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 25491da177e4SLinus Torvalds t++; 25501da177e4SLinus Torvalds if (t > imx) { 25511da177e4SLinus Torvalds t = imn; 25521da177e4SLinus Torvalds } 25531da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 25541da177e4SLinus Torvalds } 25551da177e4SLinus Torvalds } 25561da177e4SLinus Torvalds if (pkt_dev->cflows) { 2557007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2558222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2559222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2560a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2561*6f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) 2562a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2563a553e4a6SJamal Hadi Salim #endif 25641da177e4SLinus Torvalds pkt_dev->nflows++; 25651da177e4SLinus Torvalds } 25661da177e4SLinus Torvalds } 2567222f1806SLuiz Capitulino } else { /* IPV6 * */ 2568222f1806SLuiz Capitulino 256906e30411SJoe Perches if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) { 25701da177e4SLinus Torvalds int i; 25711da177e4SLinus Torvalds 25721da177e4SLinus Torvalds /* Only random destinations yet */ 25731da177e4SLinus Torvalds 25741da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 25751da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 257633d7c5e5SAkinobu Mita (((__force __be32)prandom_u32() | 25771da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 25781da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 25791da177e4SLinus Torvalds } 25801da177e4SLinus Torvalds } 25811da177e4SLinus Torvalds } 25821da177e4SLinus Torvalds 25831da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 25841da177e4SLinus Torvalds __u32 t; 25851da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 258633d7c5e5SAkinobu Mita t = prandom_u32() % 25875fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 25885fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2589222f1806SLuiz Capitulino } else { 25901da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 25911da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 25921da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 25931da177e4SLinus Torvalds } 25941da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 25951da177e4SLinus Torvalds } 25961da177e4SLinus Torvalds 2597fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 259845b270f8SRobert Olsson 25991da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 26001da177e4SLinus Torvalds } 26011da177e4SLinus Torvalds 2602a553e4a6SJamal Hadi Salim 2603a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 26045537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { 2605cf93d47eSFan Du 2606cf93d47eSFan Du [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ 2607cf93d47eSFan Du }; 2608cf93d47eSFan Du 2609a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2610a553e4a6SJamal Hadi Salim { 2611a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2612a553e4a6SJamal Hadi Salim int err = 0; 26136de9ace4SFan Du struct net *net = dev_net(pkt_dev->odev); 2614a553e4a6SJamal Hadi Salim 2615a553e4a6SJamal Hadi Salim if (!x) 2616a553e4a6SJamal Hadi Salim return 0; 2617a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2618a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2619cf93d47eSFan Du if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) 2620a553e4a6SJamal Hadi Salim return 0; 2621a553e4a6SJamal Hadi Salim 2622cf93d47eSFan Du /* But when user specify an valid SPI, transformation 2623cf93d47eSFan Du * supports both transport/tunnel mode + ESP/AH type. 2624cf93d47eSFan Du */ 2625cf93d47eSFan Du if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) 2626b6ca8bd5SDavid Miller skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF; 2627cf93d47eSFan Du 2628cf93d47eSFan Du rcu_read_lock_bh(); 262913996378SHerbert Xu err = x->outer_mode->output(x, skb); 2630cf93d47eSFan Du rcu_read_unlock_bh(); 26316de9ace4SFan Du if (err) { 26326de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); 2633a553e4a6SJamal Hadi Salim goto error; 26346de9ace4SFan Du } 2635a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 26366de9ace4SFan Du if (err) { 26376de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); 2638a553e4a6SJamal Hadi Salim goto error; 26396de9ace4SFan Du } 26400af0a413SFan Du spin_lock_bh(&x->lock); 2641a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2642a553e4a6SJamal Hadi Salim x->curlft.packets++; 26430af0a413SFan Du spin_unlock_bh(&x->lock); 2644a553e4a6SJamal Hadi Salim error: 2645a553e4a6SJamal Hadi Salim return err; 2646a553e4a6SJamal Hadi Salim } 2647a553e4a6SJamal Hadi Salim 2648475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2649a553e4a6SJamal Hadi Salim { 2650a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2651a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2652d6182223SPaul Gortmaker int i; 2653d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2654a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2655a553e4a6SJamal Hadi Salim if (x) { 2656a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2657a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2658a553e4a6SJamal Hadi Salim } 2659a553e4a6SJamal Hadi Salim } 2660a553e4a6SJamal Hadi Salim } 2661a553e4a6SJamal Hadi Salim } 2662a553e4a6SJamal Hadi Salim 2663475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2664a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2665a553e4a6SJamal Hadi Salim { 2666*6f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) { 2667a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2668a553e4a6SJamal Hadi Salim int nhead = 0; 2669a553e4a6SJamal Hadi Salim if (x) { 2670d4969581SEric Dumazet struct ethhdr *eth; 26713868204dSfan.du struct iphdr *iph; 2672d4969581SEric Dumazet int ret; 26733868204dSfan.du 2674a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2675a553e4a6SJamal Hadi Salim if (nhead > 0) { 2676a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2677a553e4a6SJamal Hadi Salim if (ret < 0) { 2678f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2679f9467eaeSJoe Perches ret); 2680b4bb4ac8SIlpo Järvinen goto err; 2681a553e4a6SJamal Hadi Salim } 2682a553e4a6SJamal Hadi Salim } 2683a553e4a6SJamal Hadi Salim 2684a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2685a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2686a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2687a553e4a6SJamal Hadi Salim if (ret) { 2688f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2689b4bb4ac8SIlpo Järvinen goto err; 2690a553e4a6SJamal Hadi Salim } 2691a553e4a6SJamal Hadi Salim /* restore ll */ 2692d58ff351SJohannes Berg eth = skb_push(skb, ETH_HLEN); 2693d4969581SEric Dumazet memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN); 2694d4969581SEric Dumazet eth->h_proto = protocol; 26953868204dSfan.du 26963868204dSfan.du /* Update IPv4 header len as well as checksum value */ 26973868204dSfan.du iph = ip_hdr(skb); 26983868204dSfan.du iph->tot_len = htons(skb->len - ETH_HLEN); 26993868204dSfan.du ip_send_check(iph); 2700a553e4a6SJamal Hadi Salim } 2701a553e4a6SJamal Hadi Salim } 2702a553e4a6SJamal Hadi Salim return 1; 2703b4bb4ac8SIlpo Järvinen err: 2704b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2705b4bb4ac8SIlpo Järvinen return 0; 2706a553e4a6SJamal Hadi Salim } 2707a553e4a6SJamal Hadi Salim #endif 2708a553e4a6SJamal Hadi Salim 2709ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2710ca6549afSSteven Whitehouse { 271195c96174SEric Dumazet unsigned int i; 271263adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2713ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 271463adc6fbSStephen Hemminger 2715ca6549afSSteven Whitehouse mpls--; 2716ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2717ca6549afSSteven Whitehouse } 2718ca6549afSSteven Whitehouse 27190f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 27200f37c605SAl Viro unsigned int prio) 27210f37c605SAl Viro { 27220f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 27230f37c605SAl Viro } 27240f37c605SAl Viro 272526ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, 272626ad7879SEric Dumazet int datalen) 272726ad7879SEric Dumazet { 27287f5d3f27SArnd Bergmann struct timespec64 timestamp; 272926ad7879SEric Dumazet struct pktgen_hdr *pgh; 273026ad7879SEric Dumazet 27314df864c1SJohannes Berg pgh = skb_put(skb, sizeof(*pgh)); 273226ad7879SEric Dumazet datalen -= sizeof(*pgh); 273326ad7879SEric Dumazet 273426ad7879SEric Dumazet if (pkt_dev->nfrags <= 0) { 2735b080db58SJohannes Berg skb_put_zero(skb, datalen); 273626ad7879SEric Dumazet } else { 273726ad7879SEric Dumazet int frags = pkt_dev->nfrags; 273826ad7879SEric Dumazet int i, len; 27397d36a991Samit salecha int frag_len; 274026ad7879SEric Dumazet 274126ad7879SEric Dumazet 274226ad7879SEric Dumazet if (frags > MAX_SKB_FRAGS) 274326ad7879SEric Dumazet frags = MAX_SKB_FRAGS; 274426ad7879SEric Dumazet len = datalen - frags * PAGE_SIZE; 274526ad7879SEric Dumazet if (len > 0) { 2746b080db58SJohannes Berg skb_put_zero(skb, len); 274726ad7879SEric Dumazet datalen = frags * PAGE_SIZE; 274826ad7879SEric Dumazet } 274926ad7879SEric Dumazet 275026ad7879SEric Dumazet i = 0; 27517d36a991Samit salecha frag_len = (datalen/frags) < PAGE_SIZE ? 27527d36a991Samit salecha (datalen/frags) : PAGE_SIZE; 275326ad7879SEric Dumazet while (datalen > 0) { 275426ad7879SEric Dumazet if (unlikely(!pkt_dev->page)) { 275526ad7879SEric Dumazet int node = numa_node_id(); 275626ad7879SEric Dumazet 275726ad7879SEric Dumazet if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE)) 275826ad7879SEric Dumazet node = pkt_dev->node; 275926ad7879SEric Dumazet pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); 276026ad7879SEric Dumazet if (!pkt_dev->page) 276126ad7879SEric Dumazet break; 276226ad7879SEric Dumazet } 2763a0bec1cdSIan Campbell get_page(pkt_dev->page); 2764ea2ab693SIan Campbell skb_frag_set_page(skb, i, pkt_dev->page); 276526ad7879SEric Dumazet skb_shinfo(skb)->frags[i].page_offset = 0; 27667d36a991Samit salecha /*last fragment, fill rest of data*/ 27677d36a991Samit salecha if (i == (frags - 1)) 27689e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], 27699e903e08SEric Dumazet (datalen < PAGE_SIZE ? datalen : PAGE_SIZE)); 27707d36a991Samit salecha else 27719e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len); 27729e903e08SEric Dumazet datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]); 27739e903e08SEric Dumazet skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 27749e903e08SEric Dumazet skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 277526ad7879SEric Dumazet i++; 277626ad7879SEric Dumazet skb_shinfo(skb)->nr_frags = i; 277726ad7879SEric Dumazet } 277826ad7879SEric Dumazet } 277926ad7879SEric Dumazet 278026ad7879SEric Dumazet /* Stamp the time, and sequence number, 278126ad7879SEric Dumazet * convert them to network byte order 278226ad7879SEric Dumazet */ 278326ad7879SEric Dumazet pgh->pgh_magic = htonl(PKTGEN_MAGIC); 278426ad7879SEric Dumazet pgh->seq_num = htonl(pkt_dev->seq_num); 278526ad7879SEric Dumazet 2786afb84b62SJesper Dangaard Brouer if (pkt_dev->flags & F_NO_TIMESTAMP) { 2787afb84b62SJesper Dangaard Brouer pgh->tv_sec = 0; 2788afb84b62SJesper Dangaard Brouer pgh->tv_usec = 0; 2789afb84b62SJesper Dangaard Brouer } else { 27907f5d3f27SArnd Bergmann /* 27917f5d3f27SArnd Bergmann * pgh->tv_sec wraps in y2106 when interpreted as unsigned 27927f5d3f27SArnd Bergmann * as done by wireshark, or y2038 when interpreted as signed. 27937f5d3f27SArnd Bergmann * This is probably harmless, but if anyone wants to improve 27947f5d3f27SArnd Bergmann * it, we could introduce a variant that puts 64-bit nanoseconds 27957f5d3f27SArnd Bergmann * into the respective header bytes. 27967f5d3f27SArnd Bergmann * This would also be slightly faster to read. 27977f5d3f27SArnd Bergmann */ 27987f5d3f27SArnd Bergmann ktime_get_real_ts64(×tamp); 279926ad7879SEric Dumazet pgh->tv_sec = htonl(timestamp.tv_sec); 28007f5d3f27SArnd Bergmann pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC); 280126ad7879SEric Dumazet } 2802afb84b62SJesper Dangaard Brouer } 280326ad7879SEric Dumazet 28047a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev, 280563d75463SPaolo Abeni struct pktgen_dev *pkt_dev) 28067a6e288dSDaniel Borkmann { 280763d75463SPaolo Abeni unsigned int extralen = LL_RESERVED_SPACE(dev); 28087a6e288dSDaniel Borkmann struct sk_buff *skb = NULL; 280963d75463SPaolo Abeni unsigned int size; 28107a6e288dSDaniel Borkmann 281163d75463SPaolo Abeni size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead; 28127a6e288dSDaniel Borkmann if (pkt_dev->flags & F_NODE) { 28137a6e288dSDaniel Borkmann int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id(); 28147a6e288dSDaniel Borkmann 28157a6e288dSDaniel Borkmann skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node); 28167a6e288dSDaniel Borkmann if (likely(skb)) { 28177a6e288dSDaniel Borkmann skb_reserve(skb, NET_SKB_PAD); 28187a6e288dSDaniel Borkmann skb->dev = dev; 28197a6e288dSDaniel Borkmann } 28207a6e288dSDaniel Borkmann } else { 28217a6e288dSDaniel Borkmann skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT); 28227a6e288dSDaniel Borkmann } 28233de03596SJohn Fastabend 282463d75463SPaolo Abeni /* the caller pre-fetches from skb->data and reserves for the mac hdr */ 28253de03596SJohn Fastabend if (likely(skb)) 282663d75463SPaolo Abeni skb_reserve(skb, extralen - 16); 28277a6e288dSDaniel Borkmann 28287a6e288dSDaniel Borkmann return skb; 28297a6e288dSDaniel Borkmann } 28307a6e288dSDaniel Borkmann 28311da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 28321da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 28331da177e4SLinus Torvalds { 28341da177e4SLinus Torvalds struct sk_buff *skb = NULL; 28351da177e4SLinus Torvalds __u8 *eth; 28361da177e4SLinus Torvalds struct udphdr *udph; 28371da177e4SLinus Torvalds int datalen, iplen; 28381da177e4SLinus Torvalds struct iphdr *iph; 2839d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2840ca6549afSSteven Whitehouse __be32 *mpls; 284134954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 284234954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 284334954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 284434954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2845fd2ea0a7SDavid S. Miller u16 queue_map; 2846ca6549afSSteven Whitehouse 2847ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2848d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 28491da177e4SLinus Torvalds 285034954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2851d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 285234954ddcSFrancesco Fondelli 285364053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 285464053beeSRobert Olsson * fields. 285564053beeSRobert Olsson */ 285664053beeSRobert Olsson mod_cur_headers(pkt_dev); 2857eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 285864053beeSRobert Olsson 285963d75463SPaolo Abeni skb = pktgen_alloc_skb(odev, pkt_dev); 28601da177e4SLinus Torvalds if (!skb) { 28611da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 28621da177e4SLinus Torvalds return NULL; 28631da177e4SLinus Torvalds } 28641da177e4SLinus Torvalds 28657a6e288dSDaniel Borkmann prefetchw(skb->data); 286663d75463SPaolo Abeni skb_reserve(skb, 16); 28671da177e4SLinus Torvalds 28681da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 2869d58ff351SJohannes Berg eth = skb_push(skb, 14); 28704df864c1SJohannes Berg mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 2871ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2872ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 287334954ddcSFrancesco Fondelli 287434954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 287534954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 28764df864c1SJohannes Berg svlan_tci = skb_put(skb, sizeof(__be16)); 28770f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 28780f37c605SAl Viro pkt_dev->svlan_cfi, 28790f37c605SAl Viro pkt_dev->svlan_p); 28804df864c1SJohannes Berg svlan_encapsulated_proto = skb_put(skb, 28814df864c1SJohannes Berg sizeof(__be16)); 2882d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 288334954ddcSFrancesco Fondelli } 28844df864c1SJohannes Berg vlan_tci = skb_put(skb, sizeof(__be16)); 28850f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 28860f37c605SAl Viro pkt_dev->vlan_cfi, 28870f37c605SAl Viro pkt_dev->vlan_p); 28884df864c1SJohannes Berg vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 2889d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 289034954ddcSFrancesco Fondelli } 289134954ddcSFrancesco Fondelli 2892c145aeb3SZhang Shengju skb_reset_mac_header(skb); 2893525cebedSThomas Graf skb_set_network_header(skb, skb->len); 28944df864c1SJohannes Berg iph = skb_put(skb, sizeof(struct iphdr)); 2895525cebedSThomas Graf 2896525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 28974df864c1SJohannes Berg udph = skb_put(skb, sizeof(struct udphdr)); 2898fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 28999e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 29009e50e3acSJohn Fastabend 29011da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2902252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 29031da177e4SLinus Torvalds 2904ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2905ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 290616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 29076af773e7SNishank Trivedi if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) 29081da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 29091da177e4SLinus Torvalds 29101da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 29111da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 29121da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 2913c26bf4a5SThomas Graf udph->check = 0; 29141da177e4SLinus Torvalds 29151da177e4SLinus Torvalds iph->ihl = 5; 29161da177e4SLinus Torvalds iph->version = 4; 29171da177e4SLinus Torvalds iph->ttl = 32; 29181ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 29191da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 29201da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 29211da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 292266ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 292366ed1e5eSEric Dumazet pkt_dev->ip_id++; 29241da177e4SLinus Torvalds iph->frag_off = 0; 29251da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 29261da177e4SLinus Torvalds iph->tot_len = htons(iplen); 292703c633e7SThomas Graf ip_send_check(iph); 2928ca6549afSSteven Whitehouse skb->protocol = protocol; 29291da177e4SLinus Torvalds skb->dev = odev; 29301da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 2931c26bf4a5SThomas Graf 29327744b5f3SSabrina Dubroca pktgen_finalize_skb(pkt_dev, skb, datalen); 29337744b5f3SSabrina Dubroca 2934c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 2935c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 2936c8cd0989STom Herbert } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) { 2937c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 2938c26bf4a5SThomas Graf skb->csum = 0; 29397744b5f3SSabrina Dubroca udp4_hwcsum(skb, iph->saddr, iph->daddr); 2940c26bf4a5SThomas Graf } else { 29417744b5f3SSabrina Dubroca __wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0); 2942c26bf4a5SThomas Graf 2943c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 29447744b5f3SSabrina Dubroca udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 2945c26bf4a5SThomas Graf datalen + 8, IPPROTO_UDP, csum); 2946c26bf4a5SThomas Graf 2947c26bf4a5SThomas Graf if (udph->check == 0) 2948c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 2949c26bf4a5SThomas Graf } 2950c26bf4a5SThomas Graf 2951a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2952a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2953a553e4a6SJamal Hadi Salim return NULL; 2954a553e4a6SJamal Hadi Salim #endif 2955a553e4a6SJamal Hadi Salim 29561da177e4SLinus Torvalds return skb; 29571da177e4SLinus Torvalds } 29581da177e4SLinus Torvalds 29591da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 29601da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29611da177e4SLinus Torvalds { 29621da177e4SLinus Torvalds struct sk_buff *skb = NULL; 29631da177e4SLinus Torvalds __u8 *eth; 29641da177e4SLinus Torvalds struct udphdr *udph; 2965c26bf4a5SThomas Graf int datalen, udplen; 29661da177e4SLinus Torvalds struct ipv6hdr *iph; 2967d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2968ca6549afSSteven Whitehouse __be32 *mpls; 296934954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 297034954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 297134954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 297234954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2973fd2ea0a7SDavid S. Miller u16 queue_map; 2974ca6549afSSteven Whitehouse 2975ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2976d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 29771da177e4SLinus Torvalds 297834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2979d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 298034954ddcSFrancesco Fondelli 298164053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 298264053beeSRobert Olsson * fields. 298364053beeSRobert Olsson */ 298464053beeSRobert Olsson mod_cur_headers(pkt_dev); 2985eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 298664053beeSRobert Olsson 298763d75463SPaolo Abeni skb = pktgen_alloc_skb(odev, pkt_dev); 29881da177e4SLinus Torvalds if (!skb) { 29891da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 29901da177e4SLinus Torvalds return NULL; 29911da177e4SLinus Torvalds } 29921da177e4SLinus Torvalds 29937a6e288dSDaniel Borkmann prefetchw(skb->data); 29941da177e4SLinus Torvalds skb_reserve(skb, 16); 29951da177e4SLinus Torvalds 29961da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 2997d58ff351SJohannes Berg eth = skb_push(skb, 14); 29984df864c1SJohannes Berg mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 2999ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 3000ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 300134954ddcSFrancesco Fondelli 300234954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 300334954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 30044df864c1SJohannes Berg svlan_tci = skb_put(skb, sizeof(__be16)); 30050f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 30060f37c605SAl Viro pkt_dev->svlan_cfi, 30070f37c605SAl Viro pkt_dev->svlan_p); 30084df864c1SJohannes Berg svlan_encapsulated_proto = skb_put(skb, 30094df864c1SJohannes Berg sizeof(__be16)); 3010d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 301134954ddcSFrancesco Fondelli } 30124df864c1SJohannes Berg vlan_tci = skb_put(skb, sizeof(__be16)); 30130f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 30140f37c605SAl Viro pkt_dev->vlan_cfi, 30150f37c605SAl Viro pkt_dev->vlan_p); 30164df864c1SJohannes Berg vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 3017d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 301834954ddcSFrancesco Fondelli } 301934954ddcSFrancesco Fondelli 3020c145aeb3SZhang Shengju skb_reset_mac_header(skb); 3021525cebedSThomas Graf skb_set_network_header(skb, skb->len); 30224df864c1SJohannes Berg iph = skb_put(skb, sizeof(struct ipv6hdr)); 3023525cebedSThomas Graf 3024525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 30254df864c1SJohannes Berg udph = skb_put(skb, sizeof(struct udphdr)); 3026fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 30279e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 3030252e3346SAl Viro *(__be16 *) ð[12] = protocol; 30311da177e4SLinus Torvalds 3032ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 3033ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 3034ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 303516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 30361da177e4SLinus Torvalds 30375aa8b572SAmerigo Wang if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { 30381da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 3039e87cc472SJoe Perches net_info_ratelimited("increased datalen to %d\n", datalen); 30401da177e4SLinus Torvalds } 30411da177e4SLinus Torvalds 3042c26bf4a5SThomas Graf udplen = datalen + sizeof(struct udphdr); 30431da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 30441da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 3045c26bf4a5SThomas Graf udph->len = htons(udplen); 3046c26bf4a5SThomas Graf udph->check = 0; 30471da177e4SLinus Torvalds 3048d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 30491da177e4SLinus Torvalds 30501ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 30511ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 3052252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 30531ca7768cSFrancesco Fondelli } 30541ca7768cSFrancesco Fondelli 30551da177e4SLinus Torvalds iph->hop_limit = 32; 30561da177e4SLinus Torvalds 3057c26bf4a5SThomas Graf iph->payload_len = htons(udplen); 30581da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 30591da177e4SLinus Torvalds 30604e3fd7a0SAlexey Dobriyan iph->daddr = pkt_dev->cur_in6_daddr; 30614e3fd7a0SAlexey Dobriyan iph->saddr = pkt_dev->cur_in6_saddr; 30621da177e4SLinus Torvalds 3063ca6549afSSteven Whitehouse skb->protocol = protocol; 30641da177e4SLinus Torvalds skb->dev = odev; 30651da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 30661da177e4SLinus Torvalds 30677744b5f3SSabrina Dubroca pktgen_finalize_skb(pkt_dev, skb, datalen); 30687744b5f3SSabrina Dubroca 3069c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 3070c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 3071c8cd0989STom Herbert } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) { 3072c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 3073c26bf4a5SThomas Graf skb->csum_start = skb_transport_header(skb) - skb->head; 3074c26bf4a5SThomas Graf skb->csum_offset = offsetof(struct udphdr, check); 3075c26bf4a5SThomas Graf udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0); 3076c26bf4a5SThomas Graf } else { 30777744b5f3SSabrina Dubroca __wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0); 3078c26bf4a5SThomas Graf 3079c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 3080c26bf4a5SThomas Graf udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum); 3081c26bf4a5SThomas Graf 3082c26bf4a5SThomas Graf if (udph->check == 0) 3083c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 3084c26bf4a5SThomas Graf } 3085c26bf4a5SThomas Graf 30861da177e4SLinus Torvalds return skb; 30871da177e4SLinus Torvalds } 30881da177e4SLinus Torvalds 3089475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 30901da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 30911da177e4SLinus Torvalds { 30921da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 30931da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 30941da177e4SLinus Torvalds else 30951da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 30961da177e4SLinus Torvalds } 30971da177e4SLinus Torvalds 30981da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 30991da177e4SLinus Torvalds { 31001da177e4SLinus Torvalds pkt_dev->seq_num = 1; 31011da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 31021da177e4SLinus Torvalds pkt_dev->sofar = 0; 31031da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 31041da177e4SLinus Torvalds pkt_dev->errors = 0; 31051da177e4SLinus Torvalds } 31061da177e4SLinus Torvalds 31071da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 31081da177e4SLinus Torvalds 31091da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 31101da177e4SLinus Torvalds { 3111c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 31121da177e4SLinus Torvalds int started = 0; 31131da177e4SLinus Torvalds 3114f9467eaeSJoe Perches func_enter(); 31151da177e4SLinus Torvalds 31168788370aSJesper Dangaard Brouer rcu_read_lock(); 31178788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 31181da177e4SLinus Torvalds 31191da177e4SLinus Torvalds /* 31201da177e4SLinus Torvalds * setup odev and create initial packet. 31211da177e4SLinus Torvalds */ 31221da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 31231da177e4SLinus Torvalds 31241da177e4SLinus Torvalds if (pkt_dev->odev) { 31251da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 31261da177e4SLinus Torvalds pkt_dev->skb = NULL; 3127398f382cSDaniel Borkmann pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); 3128fd29cf72SStephen Hemminger 312916dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 31301da177e4SLinus Torvalds 31311da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 31328788370aSJesper Dangaard Brouer pkt_dev->running = 1; /* Cranke yeself! */ 31331da177e4SLinus Torvalds started++; 3134222f1806SLuiz Capitulino } else 31351da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 31361da177e4SLinus Torvalds } 31378788370aSJesper Dangaard Brouer rcu_read_unlock(); 3138222f1806SLuiz Capitulino if (started) 3139222f1806SLuiz Capitulino t->control &= ~(T_STOP); 31401da177e4SLinus Torvalds } 31411da177e4SLinus Torvalds 31424e58a027SCong Wang static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn) 31431da177e4SLinus Torvalds { 3144cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31451da177e4SLinus Torvalds 3146f9467eaeSJoe Perches func_enter(); 31471da177e4SLinus Torvalds 31486146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3149cdcdbe0bSLuiz Capitulino 31504e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 315195ed63f7SArthur Kepner t->control |= T_STOP; 3152cdcdbe0bSLuiz Capitulino 31536146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 31541da177e4SLinus Torvalds } 31551da177e4SLinus Torvalds 3156648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 31571da177e4SLinus Torvalds { 3158648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 31591da177e4SLinus Torvalds 31608788370aSJesper Dangaard Brouer rcu_read_lock(); 31618788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 31628788370aSJesper Dangaard Brouer if (pkt_dev->running) { 31638788370aSJesper Dangaard Brouer rcu_read_unlock(); 3164648fda74SStephen Hemminger return 1; 31658788370aSJesper Dangaard Brouer } 31668788370aSJesper Dangaard Brouer rcu_read_unlock(); 3167648fda74SStephen Hemminger return 0; 31681da177e4SLinus Torvalds } 31691da177e4SLinus Torvalds 31701da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 31711da177e4SLinus Torvalds { 31721da177e4SLinus Torvalds while (thread_is_running(t)) { 31731da177e4SLinus Torvalds 31741da177e4SLinus Torvalds msleep_interruptible(100); 31751da177e4SLinus Torvalds 31761da177e4SLinus Torvalds if (signal_pending(current)) 31771da177e4SLinus Torvalds goto signal; 31781da177e4SLinus Torvalds } 31791da177e4SLinus Torvalds return 1; 31801da177e4SLinus Torvalds signal: 31811da177e4SLinus Torvalds return 0; 31821da177e4SLinus Torvalds } 31831da177e4SLinus Torvalds 31844e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn) 31851da177e4SLinus Torvalds { 3186cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31871da177e4SLinus Torvalds int sig = 1; 31881da177e4SLinus Torvalds 31896146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3190cdcdbe0bSLuiz Capitulino 31914e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 31921da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3193222f1806SLuiz Capitulino if (sig == 0) 3194222f1806SLuiz Capitulino break; 31951da177e4SLinus Torvalds } 3196cdcdbe0bSLuiz Capitulino 3197cdcdbe0bSLuiz Capitulino if (sig == 0) 31984e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 31991da177e4SLinus Torvalds t->control |= (T_STOP); 3200cdcdbe0bSLuiz Capitulino 32016146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32021da177e4SLinus Torvalds return sig; 32031da177e4SLinus Torvalds } 32041da177e4SLinus Torvalds 32054e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn) 32061da177e4SLinus Torvalds { 3207cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32081da177e4SLinus Torvalds 3209f9467eaeSJoe Perches func_enter(); 32101da177e4SLinus Torvalds 32116146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 32121da177e4SLinus Torvalds 32134e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 32141da177e4SLinus Torvalds t->control |= (T_RUN); 3215cdcdbe0bSLuiz Capitulino 32166146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32171da177e4SLinus Torvalds 321863adc6fbSStephen Hemminger /* Propagate thread->control */ 321963adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 32201da177e4SLinus Torvalds 32214e58a027SCong Wang pktgen_wait_all_threads_run(pn); 32221da177e4SLinus Torvalds } 32231da177e4SLinus Torvalds 32244e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn) 3225eb37b41cSJesse Brandeburg { 3226eb37b41cSJesse Brandeburg struct pktgen_thread *t; 3227eb37b41cSJesse Brandeburg 3228f9467eaeSJoe Perches func_enter(); 3229eb37b41cSJesse Brandeburg 3230eb37b41cSJesse Brandeburg mutex_lock(&pktgen_thread_lock); 3231eb37b41cSJesse Brandeburg 32324e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 3233eb37b41cSJesse Brandeburg t->control |= (T_REMDEVALL); 3234eb37b41cSJesse Brandeburg 3235eb37b41cSJesse Brandeburg mutex_unlock(&pktgen_thread_lock); 3236eb37b41cSJesse Brandeburg 323763adc6fbSStephen Hemminger /* Propagate thread->control */ 323863adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3239eb37b41cSJesse Brandeburg 32404e58a027SCong Wang pktgen_wait_all_threads_run(pn); 3241eb37b41cSJesse Brandeburg } 3242eb37b41cSJesse Brandeburg 32431da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 32441da177e4SLinus Torvalds { 3245fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 32461da177e4SLinus Torvalds char *p = pkt_dev->result; 3247fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3248fd29cf72SStephen Hemminger pkt_dev->started_at); 3249fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 32501da177e4SLinus Torvalds 325103a14ab1SDaniel Turull p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 3252fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3253fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3254fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 32551da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 32561da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 32571da177e4SLinus Torvalds 3258fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3259fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 32601da177e4SLinus Torvalds 32611da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 32621da177e4SLinus Torvalds 32631da177e4SLinus Torvalds mbps = bps; 32641da177e4SLinus Torvalds do_div(mbps, 1000000); 32651da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 32661da177e4SLinus Torvalds (unsigned long long)pps, 32671da177e4SLinus Torvalds (unsigned long long)mbps, 32681da177e4SLinus Torvalds (unsigned long long)bps, 32691da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 32701da177e4SLinus Torvalds } 32711da177e4SLinus Torvalds 32721da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 32731da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 32741da177e4SLinus Torvalds { 3275222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 32761da177e4SLinus Torvalds 32771da177e4SLinus Torvalds if (!pkt_dev->running) { 3278294a0b7fSJoe Perches pr_warn("interface: %s is already stopped\n", 3279f9467eaeSJoe Perches pkt_dev->odevname); 32801da177e4SLinus Torvalds return -EINVAL; 32811da177e4SLinus Torvalds } 32821da177e4SLinus Torvalds 32838788370aSJesper Dangaard Brouer pkt_dev->running = 0; 32843bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 32853bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3286398f382cSDaniel Borkmann pkt_dev->stopped_at = ktime_get(); 32871da177e4SLinus Torvalds 328895ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 32891da177e4SLinus Torvalds 32901da177e4SLinus Torvalds return 0; 32911da177e4SLinus Torvalds } 32921da177e4SLinus Torvalds 32931da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 32941da177e4SLinus Torvalds { 3295c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 32961da177e4SLinus Torvalds 32978788370aSJesper Dangaard Brouer rcu_read_lock(); 32988788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3299c26a8016SLuiz Capitulino if (!pkt_dev->running) 3300222f1806SLuiz Capitulino continue; 3301222f1806SLuiz Capitulino if (best == NULL) 3302c26a8016SLuiz Capitulino best = pkt_dev; 3303398f382cSDaniel Borkmann else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) 3304c26a8016SLuiz Capitulino best = pkt_dev; 33051da177e4SLinus Torvalds } 33068788370aSJesper Dangaard Brouer rcu_read_unlock(); 33078788370aSJesper Dangaard Brouer 33081da177e4SLinus Torvalds return best; 33091da177e4SLinus Torvalds } 33101da177e4SLinus Torvalds 3311222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3312222f1806SLuiz Capitulino { 3313c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 33141da177e4SLinus Torvalds 3315f9467eaeSJoe Perches func_enter(); 33161da177e4SLinus Torvalds 33178788370aSJesper Dangaard Brouer rcu_read_lock(); 33181da177e4SLinus Torvalds 33198788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3320c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 332195ed63f7SArthur Kepner } 332295ed63f7SArthur Kepner 33238788370aSJesper Dangaard Brouer rcu_read_unlock(); 332495ed63f7SArthur Kepner } 332595ed63f7SArthur Kepner 332695ed63f7SArthur Kepner /* 332795ed63f7SArthur Kepner * one of our devices needs to be removed - find it 332895ed63f7SArthur Kepner * and remove it 332995ed63f7SArthur Kepner */ 333095ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 333195ed63f7SArthur Kepner { 3332c26a8016SLuiz Capitulino struct list_head *q, *n; 3333c26a8016SLuiz Capitulino struct pktgen_dev *cur; 333495ed63f7SArthur Kepner 3335f9467eaeSJoe Perches func_enter(); 333695ed63f7SArthur Kepner 3337c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3338c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 333995ed63f7SArthur Kepner 3340222f1806SLuiz Capitulino if (!cur->removal_mark) 3341222f1806SLuiz Capitulino continue; 334295ed63f7SArthur Kepner 334395ed63f7SArthur Kepner kfree_skb(cur->skb); 334495ed63f7SArthur Kepner cur->skb = NULL; 334595ed63f7SArthur Kepner 334695ed63f7SArthur Kepner pktgen_remove_device(t, cur); 334795ed63f7SArthur Kepner 334895ed63f7SArthur Kepner break; 334995ed63f7SArthur Kepner } 33501da177e4SLinus Torvalds } 33511da177e4SLinus Torvalds 33521da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 33531da177e4SLinus Torvalds { 3354c26a8016SLuiz Capitulino struct list_head *q, *n; 3355c26a8016SLuiz Capitulino struct pktgen_dev *cur; 33561da177e4SLinus Torvalds 3357f9467eaeSJoe Perches func_enter(); 3358f9467eaeSJoe Perches 33591da177e4SLinus Torvalds /* Remove all devices, free mem */ 33601da177e4SLinus Torvalds 3361c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3362c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 336395ed63f7SArthur Kepner 336495ed63f7SArthur Kepner kfree_skb(cur->skb); 336595ed63f7SArthur Kepner cur->skb = NULL; 336695ed63f7SArthur Kepner 33671da177e4SLinus Torvalds pktgen_remove_device(t, cur); 33681da177e4SLinus Torvalds } 33691da177e4SLinus Torvalds } 33701da177e4SLinus Torvalds 33711da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 33721da177e4SLinus Torvalds { 33731da177e4SLinus Torvalds /* Remove from the thread list */ 33744e58a027SCong Wang remove_proc_entry(t->tsk->comm, t->net->proc_dir); 33751da177e4SLinus Torvalds } 33761da177e4SLinus Torvalds 3377ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 33783791decbSStephen Hemminger { 3379398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 33803791decbSStephen Hemminger schedule(); 3381398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 33823791decbSStephen Hemminger } 33833791decbSStephen Hemminger 3384ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3385ef87979cSStephen Hemminger { 3386398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 3387ef87979cSStephen Hemminger 338863354797SReshetova, Elena while (refcount_read(&(pkt_dev->skb->users)) != 1) { 3389ef87979cSStephen Hemminger if (signal_pending(current)) 3390ef87979cSStephen Hemminger break; 3391ef87979cSStephen Hemminger 3392ef87979cSStephen Hemminger if (need_resched()) 3393ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3394ef87979cSStephen Hemminger else 3395ef87979cSStephen Hemminger cpu_relax(); 3396ef87979cSStephen Hemminger } 3397398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 3398ef87979cSStephen Hemminger } 3399fd29cf72SStephen Hemminger 3400475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 34011da177e4SLinus Torvalds { 34026aa7de05SMark Rutland unsigned int burst = READ_ONCE(pkt_dev->burst); 340300829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 3404fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 340562f64aedSAlexei Starovoitov struct sk_buff *skb; 34061da177e4SLinus Torvalds int ret; 34071da177e4SLinus Torvalds 3408ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3409ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 34101da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34113791decbSStephen Hemminger return; 34121da177e4SLinus Torvalds } 34131da177e4SLinus Torvalds 3414ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3415ef87979cSStephen Hemminger * "never transmit" 3416ef87979cSStephen Hemminger */ 3417ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3418398f382cSDaniel Borkmann pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX); 3419ef87979cSStephen Hemminger return; 3420ef87979cSStephen Hemminger } 3421ef87979cSStephen Hemminger 3422ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 34237d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 34247d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 34251da177e4SLinus Torvalds /* build a new pkt */ 34261da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 34271da177e4SLinus Torvalds 34281da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 34291da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3430f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 34311da177e4SLinus Torvalds schedule(); 34321da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 34333791decbSStephen Hemminger return; 34341da177e4SLinus Torvalds } 3435baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 34361da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 34371da177e4SLinus Torvalds } 34381da177e4SLinus Torvalds 3439ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3440ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3441ef87979cSStephen Hemminger 344262f64aedSAlexei Starovoitov if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) { 344362f64aedSAlexei Starovoitov skb = pkt_dev->skb; 344462f64aedSAlexei Starovoitov skb->protocol = eth_type_trans(skb, skb->dev); 344563354797SReshetova, Elena refcount_add(burst, &skb->users); 344662f64aedSAlexei Starovoitov local_bh_disable(); 344762f64aedSAlexei Starovoitov do { 344862f64aedSAlexei Starovoitov ret = netif_receive_skb(skb); 344962f64aedSAlexei Starovoitov if (ret == NET_RX_DROP) 345062f64aedSAlexei Starovoitov pkt_dev->errors++; 345162f64aedSAlexei Starovoitov pkt_dev->sofar++; 345262f64aedSAlexei Starovoitov pkt_dev->seq_num++; 345363354797SReshetova, Elena if (refcount_read(&skb->users) != burst) { 345462f64aedSAlexei Starovoitov /* skb was queued by rps/rfs or taps, 345562f64aedSAlexei Starovoitov * so cannot reuse this skb 345662f64aedSAlexei Starovoitov */ 345763354797SReshetova, Elena WARN_ON(refcount_sub_and_test(burst - 1, &skb->users)); 345862f64aedSAlexei Starovoitov /* get out of the loop and wait 345962f64aedSAlexei Starovoitov * until skb is consumed 346062f64aedSAlexei Starovoitov */ 346162f64aedSAlexei Starovoitov break; 346262f64aedSAlexei Starovoitov } 346362f64aedSAlexei Starovoitov /* skb was 'freed' by stack, so clean few 346462f64aedSAlexei Starovoitov * bits and reuse it 346562f64aedSAlexei Starovoitov */ 3466a5135bcfSWillem de Bruijn skb_reset_tc(skb); 346762f64aedSAlexei Starovoitov } while (--burst > 0); 346862f64aedSAlexei Starovoitov goto out; /* Skips xmit_mode M_START_XMIT */ 34690967f244SJohn Fastabend } else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) { 34700967f244SJohn Fastabend local_bh_disable(); 347163354797SReshetova, Elena refcount_inc(&pkt_dev->skb->users); 34720967f244SJohn Fastabend 34730967f244SJohn Fastabend ret = dev_queue_xmit(pkt_dev->skb); 34740967f244SJohn Fastabend switch (ret) { 34750967f244SJohn Fastabend case NET_XMIT_SUCCESS: 34760967f244SJohn Fastabend pkt_dev->sofar++; 34770967f244SJohn Fastabend pkt_dev->seq_num++; 34780967f244SJohn Fastabend pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 34790967f244SJohn Fastabend break; 34800967f244SJohn Fastabend case NET_XMIT_DROP: 34810967f244SJohn Fastabend case NET_XMIT_CN: 34820967f244SJohn Fastabend /* These are all valid return codes for a qdisc but 34830967f244SJohn Fastabend * indicate packets are being dropped or will likely 34840967f244SJohn Fastabend * be dropped soon. 34850967f244SJohn Fastabend */ 34860967f244SJohn Fastabend case NETDEV_TX_BUSY: 34870967f244SJohn Fastabend /* qdisc may call dev_hard_start_xmit directly in cases 34880967f244SJohn Fastabend * where no queues exist e.g. loopback device, virtual 34890967f244SJohn Fastabend * devices, etc. In this case we need to handle 34900967f244SJohn Fastabend * NETDEV_TX_ codes. 34910967f244SJohn Fastabend */ 34920967f244SJohn Fastabend default: 34930967f244SJohn Fastabend pkt_dev->errors++; 34940967f244SJohn Fastabend net_info_ratelimited("%s xmit error: %d\n", 34950967f244SJohn Fastabend pkt_dev->odevname, ret); 34960967f244SJohn Fastabend break; 34970967f244SJohn Fastabend } 34980967f244SJohn Fastabend goto out; 349962f64aedSAlexei Starovoitov } 350062f64aedSAlexei Starovoitov 350110c51b56SDaniel Borkmann txq = skb_get_tx_queue(odev, pkt_dev->skb); 3502fd2ea0a7SDavid S. Miller 35030f2eea4bSDaniel Borkmann local_bh_disable(); 35040f2eea4bSDaniel Borkmann 35050f2eea4bSDaniel Borkmann HARD_TX_LOCK(odev, txq, smp_processor_id()); 35065b8db2f5SStephen Hemminger 35076f25cd47SDaniel Borkmann if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) { 3508ef87979cSStephen Hemminger ret = NETDEV_TX_BUSY; 35090835acfeSEric Dumazet pkt_dev->last_ok = 0; 35100835acfeSEric Dumazet goto unlock; 35110835acfeSEric Dumazet } 351263354797SReshetova, Elena refcount_add(burst, &pkt_dev->skb->users); 351338b2cf29SAlexei Starovoitov 351438b2cf29SAlexei Starovoitov xmit_more: 351538b2cf29SAlexei Starovoitov ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); 3516ef87979cSStephen Hemminger 35175b8db2f5SStephen Hemminger switch (ret) { 35185b8db2f5SStephen Hemminger case NETDEV_TX_OK: 35191da177e4SLinus Torvalds pkt_dev->last_ok = 1; 35201da177e4SLinus Torvalds pkt_dev->sofar++; 35211da177e4SLinus Torvalds pkt_dev->seq_num++; 3522baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 352338b2cf29SAlexei Starovoitov if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq)) 352438b2cf29SAlexei Starovoitov goto xmit_more; 35255b8db2f5SStephen Hemminger break; 3526f466dba1SJohn Fastabend case NET_XMIT_DROP: 3527f466dba1SJohn Fastabend case NET_XMIT_CN: 3528f466dba1SJohn Fastabend /* skb has been consumed */ 3529f466dba1SJohn Fastabend pkt_dev->errors++; 3530f466dba1SJohn Fastabend break; 35315b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 3532e87cc472SJoe Perches net_info_ratelimited("%s xmit error: %d\n", 3533e87cc472SJoe Perches pkt_dev->odevname, ret); 35341da177e4SLinus Torvalds pkt_dev->errors++; 35355b8db2f5SStephen Hemminger /* fallthru */ 35365b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 35375b8db2f5SStephen Hemminger /* Retry it next time */ 353863354797SReshetova, Elena refcount_dec(&(pkt_dev->skb->users)); 35391da177e4SLinus Torvalds pkt_dev->last_ok = 0; 35401da177e4SLinus Torvalds } 354138b2cf29SAlexei Starovoitov if (unlikely(burst)) 354263354797SReshetova, Elena WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users)); 35430835acfeSEric Dumazet unlock: 35440f2eea4bSDaniel Borkmann HARD_TX_UNLOCK(odev, txq); 35450f2eea4bSDaniel Borkmann 354662f64aedSAlexei Starovoitov out: 35470f2eea4bSDaniel Borkmann local_bh_enable(); 35481da177e4SLinus Torvalds 35491da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 35501da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3551ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 35521da177e4SLinus Torvalds 35531da177e4SLinus Torvalds /* Done with this */ 35541da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 35551da177e4SLinus Torvalds } 35561da177e4SLinus Torvalds } 35571da177e4SLinus Torvalds 35581da177e4SLinus Torvalds /* 35591da177e4SLinus Torvalds * Main loop of the thread goes here 35601da177e4SLinus Torvalds */ 35611da177e4SLinus Torvalds 3562ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 35631da177e4SLinus Torvalds { 35641da177e4SLinus Torvalds DEFINE_WAIT(wait); 3565ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 35661da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 35671da177e4SLinus Torvalds int cpu = t->cpu; 35681da177e4SLinus Torvalds 3569ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 35701da177e4SLinus Torvalds 35711da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3572d3ede327SDenis V. Lunev complete(&t->start_done); 35731da177e4SLinus Torvalds 3574f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 35751da177e4SLinus Torvalds 357683144186SRafael J. Wysocki set_freezable(); 357783144186SRafael J. Wysocki 3578ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3579ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3580ee74baa7SDavid S. Miller 3581ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 35824e58a027SCong Wang if (t->net->pktgen_exiting) 3583551eaff1SEric Dumazet break; 3584ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3585ef87979cSStephen Hemminger t->control != 0, 3586ef87979cSStephen Hemminger HZ/10); 35871b3f720bSRafael J. Wysocki try_to_freeze(); 3588ef87979cSStephen Hemminger continue; 3589ee74baa7SDavid S. Miller } 35901da177e4SLinus Torvalds 3591ef87979cSStephen Hemminger if (likely(pkt_dev)) { 35921da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 35931da177e4SLinus Torvalds 3594ef87979cSStephen Hemminger if (need_resched()) 3595ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3596ef87979cSStephen Hemminger else 3597ef87979cSStephen Hemminger cpu_relax(); 3598ef87979cSStephen Hemminger } 3599ef87979cSStephen Hemminger 36001da177e4SLinus Torvalds if (t->control & T_STOP) { 36011da177e4SLinus Torvalds pktgen_stop(t); 36021da177e4SLinus Torvalds t->control &= ~(T_STOP); 36031da177e4SLinus Torvalds } 36041da177e4SLinus Torvalds 36051da177e4SLinus Torvalds if (t->control & T_RUN) { 36061da177e4SLinus Torvalds pktgen_run(t); 36071da177e4SLinus Torvalds t->control &= ~(T_RUN); 36081da177e4SLinus Torvalds } 36091da177e4SLinus Torvalds 361095ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 36111da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 361295ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 361395ed63f7SArthur Kepner } 361495ed63f7SArthur Kepner 361595ed63f7SArthur Kepner if (t->control & T_REMDEV) { 361695ed63f7SArthur Kepner pktgen_rem_one_if(t); 36171da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 36181da177e4SLinus Torvalds } 36191da177e4SLinus Torvalds 362009fe3ef4SAndrew Morton try_to_freeze(); 36211da177e4SLinus Torvalds } 36221da177e4SLinus Torvalds 3623f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 36241da177e4SLinus Torvalds pktgen_stop(t); 36251da177e4SLinus Torvalds 3626f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 36271da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 36281da177e4SLinus Torvalds 3629f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 36301da177e4SLinus Torvalds pktgen_rem_thread(t); 3631cdcdbe0bSLuiz Capitulino 3632ee74baa7SDavid S. Miller return 0; 36331da177e4SLinus Torvalds } 36341da177e4SLinus Torvalds 3635222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 36363e984840SEric Dumazet const char *ifname, bool exact) 36371da177e4SLinus Torvalds { 3638c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 36393e984840SEric Dumazet size_t len = strlen(ifname); 36401da177e4SLinus Torvalds 36418788370aSJesper Dangaard Brouer rcu_read_lock(); 36428788370aSJesper Dangaard Brouer list_for_each_entry_rcu(p, &t->if_list, list) 36433e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 36443e984840SEric Dumazet if (p->odevname[len]) { 36453e984840SEric Dumazet if (exact || p->odevname[len] != '@') 36463e984840SEric Dumazet continue; 36473e984840SEric Dumazet } 3648c26a8016SLuiz Capitulino pkt_dev = p; 36491da177e4SLinus Torvalds break; 36501da177e4SLinus Torvalds } 36511da177e4SLinus Torvalds 36528788370aSJesper Dangaard Brouer rcu_read_unlock(); 3653f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 36541da177e4SLinus Torvalds return pkt_dev; 36551da177e4SLinus Torvalds } 36561da177e4SLinus Torvalds 36571da177e4SLinus Torvalds /* 36581da177e4SLinus Torvalds * Adds a dev at front of if_list. 36591da177e4SLinus Torvalds */ 36601da177e4SLinus Torvalds 3661222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3662222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36631da177e4SLinus Torvalds { 36641da177e4SLinus Torvalds int rv = 0; 36651da177e4SLinus Torvalds 36668788370aSJesper Dangaard Brouer /* This function cannot be called concurrently, as its called 36678788370aSJesper Dangaard Brouer * under pktgen_thread_lock mutex, but it can run from 36688788370aSJesper Dangaard Brouer * userspace on another CPU than the kthread. The if_lock() 36698788370aSJesper Dangaard Brouer * is used here to sync with concurrent instances of 36708788370aSJesper Dangaard Brouer * _rem_dev_from_if_list() invoked via kthread, which is also 36718788370aSJesper Dangaard Brouer * updating the if_list */ 36721da177e4SLinus Torvalds if_lock(t); 36731da177e4SLinus Torvalds 36741da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3675f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 36761da177e4SLinus Torvalds rv = -EBUSY; 36771da177e4SLinus Torvalds goto out; 36781da177e4SLinus Torvalds } 3679c26a8016SLuiz Capitulino 36801da177e4SLinus Torvalds pkt_dev->running = 0; 36818788370aSJesper Dangaard Brouer pkt_dev->pg_thread = t; 36828788370aSJesper Dangaard Brouer list_add_rcu(&pkt_dev->list, &t->if_list); 36831da177e4SLinus Torvalds 36841da177e4SLinus Torvalds out: 36851da177e4SLinus Torvalds if_unlock(t); 36861da177e4SLinus Torvalds return rv; 36871da177e4SLinus Torvalds } 36881da177e4SLinus Torvalds 36891da177e4SLinus Torvalds /* Called under thread lock */ 36901da177e4SLinus Torvalds 36911da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 36921da177e4SLinus Torvalds { 36931da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 369439df232fSStephen Hemminger int err; 36953291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 36961da177e4SLinus Torvalds 36971da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 36981da177e4SLinus Torvalds 36994e58a027SCong Wang pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND); 3700d50a6b56SStephen Hemminger if (pkt_dev) { 3701f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3702d50a6b56SStephen Hemminger return -EBUSY; 3703d50a6b56SStephen Hemminger } 37041da177e4SLinus Torvalds 37053291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 37061da177e4SLinus Torvalds if (!pkt_dev) 37071da177e4SLinus Torvalds return -ENOMEM; 37081da177e4SLinus Torvalds 3709593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 371068d5ac2eSWANG Cong pkt_dev->flows = vzalloc_node(MAX_CFLOWS * sizeof(struct flow_state), 37113291b9dbSEric Dumazet node); 37121da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 37131da177e4SLinus Torvalds kfree(pkt_dev); 37141da177e4SLinus Torvalds return -ENOMEM; 37151da177e4SLinus Torvalds } 37161da177e4SLinus Torvalds 371795ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 37181da177e4SLinus Torvalds pkt_dev->nfrags = 0; 3719fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 37201da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 37211da177e4SLinus Torvalds pkt_dev->sofar = 0; 37221da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 37231da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 37241da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 37251da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 372634954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 372734954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 372834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 372934954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 373034954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 373134954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 373238b2cf29SAlexei Starovoitov pkt_dev->burst = 1; 3733e99b99b4SRobert Olsson pkt_dev->node = -1; 373434954ddcSFrancesco Fondelli 37354e58a027SCong Wang err = pktgen_setup_dev(t->net, pkt_dev, ifname); 373639df232fSStephen Hemminger if (err) 373739df232fSStephen Hemminger goto out1; 3738d8873315SNeil Horman if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) 3739d8873315SNeil Horman pkt_dev->clone_skb = pg_clone_skb_d; 37401da177e4SLinus Torvalds 37414e58a027SCong Wang pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir, 37425efdccbcSDenis V. Lunev &pktgen_if_fops, pkt_dev); 374339df232fSStephen Hemminger if (!pkt_dev->entry) { 3744f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3745d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 374639df232fSStephen Hemminger err = -EINVAL; 374739df232fSStephen Hemminger goto out2; 374839df232fSStephen Hemminger } 3749a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3750a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3751a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3752cf93d47eSFan Du 3753cf93d47eSFan Du /* xfrm tunnel mode needs additional dst to extract outter 3754cf93d47eSFan Du * ip header protocol/ttl/id field, here creat a phony one. 3755cf93d47eSFan Du * instead of looking for a valid rt, which definitely hurting 3756cf93d47eSFan Du * performance under such circumstance. 3757cf93d47eSFan Du */ 3758cf93d47eSFan Du pkt_dev->dstops.family = AF_INET; 3759b6ca8bd5SDavid Miller pkt_dev->xdst.u.dst.dev = pkt_dev->odev; 3760b6ca8bd5SDavid Miller dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false); 3761b6ca8bd5SDavid Miller pkt_dev->xdst.child = &pkt_dev->xdst.u.dst; 3762b6ca8bd5SDavid Miller pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops; 3763a553e4a6SJamal Hadi Salim #endif 376439df232fSStephen Hemminger 376539df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 376639df232fSStephen Hemminger out2: 376739df232fSStephen Hemminger dev_put(pkt_dev->odev); 376839df232fSStephen Hemminger out1: 3769a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3770a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3771a553e4a6SJamal Hadi Salim #endif 37721da177e4SLinus Torvalds vfree(pkt_dev->flows); 37731da177e4SLinus Torvalds kfree(pkt_dev); 377439df232fSStephen Hemminger return err; 37751da177e4SLinus Torvalds } 37761da177e4SLinus Torvalds 37774e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) 37781da177e4SLinus Torvalds { 3779cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3780d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3781ee74baa7SDavid S. Miller struct task_struct *p; 37821da177e4SLinus Torvalds 37833291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 37843291b9dbSEric Dumazet cpu_to_node(cpu)); 37851da177e4SLinus Torvalds if (!t) { 3786f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 37871da177e4SLinus Torvalds return -ENOMEM; 37881da177e4SLinus Torvalds } 37891da177e4SLinus Torvalds 37909a0b1e8bSEric Dumazet mutex_init(&t->if_lock); 37911da177e4SLinus Torvalds t->cpu = cpu; 37921da177e4SLinus Torvalds 3793ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3794ee74baa7SDavid S. Miller 37954e58a027SCong Wang list_add_tail(&t->th_list, &pn->pktgen_threads); 3796d3ede327SDenis V. Lunev init_completion(&t->start_done); 3797ee74baa7SDavid S. Miller 379894dcf29aSEric Dumazet p = kthread_create_on_node(pktgen_thread_worker, 379994dcf29aSEric Dumazet t, 380094dcf29aSEric Dumazet cpu_to_node(cpu), 380194dcf29aSEric Dumazet "kpktgend_%d", cpu); 3802ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3803f9467eaeSJoe Perches pr_err("kernel_thread() failed for cpu %d\n", t->cpu); 3804ee74baa7SDavid S. Miller list_del(&t->th_list); 3805ee74baa7SDavid S. Miller kfree(t); 3806ee74baa7SDavid S. Miller return PTR_ERR(p); 3807ee74baa7SDavid S. Miller } 3808ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3809ee74baa7SDavid S. Miller t->tsk = p; 3810ee74baa7SDavid S. Miller 38114e58a027SCong Wang pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir, 38125efdccbcSDenis V. Lunev &pktgen_thread_fops, t); 3813d50a6b56SStephen Hemminger if (!pe) { 3814f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3815ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3816ee74baa7SDavid S. Miller kthread_stop(p); 3817ee74baa7SDavid S. Miller list_del(&t->th_list); 38181da177e4SLinus Torvalds kfree(t); 38191da177e4SLinus Torvalds return -EINVAL; 38201da177e4SLinus Torvalds } 3821d50a6b56SStephen Hemminger 38224e58a027SCong Wang t->net = pn; 38231fbe4b46SOleg Nesterov get_task_struct(p); 3824ee74baa7SDavid S. Miller wake_up_process(p); 3825d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 38261da177e4SLinus Torvalds 38271da177e4SLinus Torvalds return 0; 38281da177e4SLinus Torvalds } 38291da177e4SLinus Torvalds 38301da177e4SLinus Torvalds /* 38311da177e4SLinus Torvalds * Removes a device from the thread if_list. 38321da177e4SLinus Torvalds */ 3833222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3834222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38351da177e4SLinus Torvalds { 3836c26a8016SLuiz Capitulino struct list_head *q, *n; 3837c26a8016SLuiz Capitulino struct pktgen_dev *p; 38381da177e4SLinus Torvalds 38398788370aSJesper Dangaard Brouer if_lock(t); 3840c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3841c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3842c26a8016SLuiz Capitulino if (p == pkt_dev) 38438788370aSJesper Dangaard Brouer list_del_rcu(&p->list); 38441da177e4SLinus Torvalds } 38458788370aSJesper Dangaard Brouer if_unlock(t); 38461da177e4SLinus Torvalds } 38471da177e4SLinus Torvalds 3848222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3849222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38501da177e4SLinus Torvalds { 3851f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 38521da177e4SLinus Torvalds 38531da177e4SLinus Torvalds if (pkt_dev->running) { 3854294a0b7fSJoe Perches pr_warn("WARNING: trying to remove a running interface, stopping it now\n"); 38551da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 38561da177e4SLinus Torvalds } 38571da177e4SLinus Torvalds 38581da177e4SLinus Torvalds /* Dis-associate from the interface */ 38591da177e4SLinus Torvalds 38601da177e4SLinus Torvalds if (pkt_dev->odev) { 38611da177e4SLinus Torvalds dev_put(pkt_dev->odev); 38621da177e4SLinus Torvalds pkt_dev->odev = NULL; 38631da177e4SLinus Torvalds } 38641da177e4SLinus Torvalds 38658788370aSJesper Dangaard Brouer /* Remove proc before if_list entry, because add_device uses 38668788370aSJesper Dangaard Brouer * list to determine if interface already exist, avoid race 38678788370aSJesper Dangaard Brouer * with proc_create_data() */ 3868a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 38691da177e4SLinus Torvalds 38708788370aSJesper Dangaard Brouer /* And update the thread if_list */ 38718788370aSJesper Dangaard Brouer _rem_dev_from_if_list(t, pkt_dev); 38728788370aSJesper Dangaard Brouer 3873a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3874a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3875a553e4a6SJamal Hadi Salim #endif 38761da177e4SLinus Torvalds vfree(pkt_dev->flows); 387726ad7879SEric Dumazet if (pkt_dev->page) 387826ad7879SEric Dumazet put_page(pkt_dev->page); 38798788370aSJesper Dangaard Brouer kfree_rcu(pkt_dev, rcu); 38801da177e4SLinus Torvalds return 0; 38811da177e4SLinus Torvalds } 38821da177e4SLinus Torvalds 38834e58a027SCong Wang static int __net_init pg_net_init(struct net *net) 38841da177e4SLinus Torvalds { 38854e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3886d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 38874e58a027SCong Wang int cpu, ret = 0; 3888d50a6b56SStephen Hemminger 38894e58a027SCong Wang pn->net = net; 38904e58a027SCong Wang INIT_LIST_HEAD(&pn->pktgen_threads); 38914e58a027SCong Wang pn->pktgen_exiting = false; 38924e58a027SCong Wang pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net); 38934e58a027SCong Wang if (!pn->proc_dir) { 38944e58a027SCong Wang pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); 3895d50a6b56SStephen Hemminger return -ENODEV; 38961da177e4SLinus Torvalds } 38974e58a027SCong Wang pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops); 38984e58a027SCong Wang if (pe == NULL) { 38994e58a027SCong Wang pr_err("cannot create %s procfs entry\n", PGCTRL); 39004e58a027SCong Wang ret = -EINVAL; 39014e58a027SCong Wang goto remove; 39024e58a027SCong Wang } 39031da177e4SLinus Torvalds 3904670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 39058024bb24SLuiz Capitulino int err; 39061da177e4SLinus Torvalds 39074e58a027SCong Wang err = pktgen_create_thread(cpu, pn); 39088024bb24SLuiz Capitulino if (err) 39094e58a027SCong Wang pr_warn("Cannot create thread for cpu %d (%d)\n", 3910f9467eaeSJoe Perches cpu, err); 39111da177e4SLinus Torvalds } 39128024bb24SLuiz Capitulino 39134e58a027SCong Wang if (list_empty(&pn->pktgen_threads)) { 39144e58a027SCong Wang pr_err("Initialization failed for all threads\n"); 3915ce14f894SWANG Cong ret = -ENODEV; 39164e58a027SCong Wang goto remove_entry; 39178024bb24SLuiz Capitulino } 39188024bb24SLuiz Capitulino 39191da177e4SLinus Torvalds return 0; 3920ce14f894SWANG Cong 39214e58a027SCong Wang remove_entry: 39224e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 39234e58a027SCong Wang remove: 3924ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 3925ce14f894SWANG Cong return ret; 39261da177e4SLinus Torvalds } 39271da177e4SLinus Torvalds 39284e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net) 39291da177e4SLinus Torvalds { 39304e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3931cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3932cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 3933d4b11335SEric Dumazet LIST_HEAD(list); 39341da177e4SLinus Torvalds 39351da177e4SLinus Torvalds /* Stop all interfaces & threads */ 39364e58a027SCong Wang pn->pktgen_exiting = true; 39371da177e4SLinus Torvalds 3938c57b5468SEric Dumazet mutex_lock(&pktgen_thread_lock); 39394e58a027SCong Wang list_splice_init(&pn->pktgen_threads, &list); 3940c57b5468SEric Dumazet mutex_unlock(&pktgen_thread_lock); 3941c57b5468SEric Dumazet 3942c57b5468SEric Dumazet list_for_each_safe(q, n, &list) { 3943cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3944c57b5468SEric Dumazet list_del(&t->th_list); 3945ee74baa7SDavid S. Miller kthread_stop(t->tsk); 39461fbe4b46SOleg Nesterov put_task_struct(t->tsk); 3947ee74baa7SDavid S. Miller kfree(t); 39481da177e4SLinus Torvalds } 39491da177e4SLinus Torvalds 39504e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 3951ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 39524e58a027SCong Wang } 39531da177e4SLinus Torvalds 39544e58a027SCong Wang static struct pernet_operations pg_net_ops = { 39554e58a027SCong Wang .init = pg_net_init, 39564e58a027SCong Wang .exit = pg_net_exit, 39574e58a027SCong Wang .id = &pg_net_id, 39584e58a027SCong Wang .size = sizeof(struct pktgen_net), 39594e58a027SCong Wang }; 39604e58a027SCong Wang 39614e58a027SCong Wang static int __init pg_init(void) 39624e58a027SCong Wang { 39634e58a027SCong Wang int ret = 0; 39644e58a027SCong Wang 39654e58a027SCong Wang pr_info("%s", version); 39664e58a027SCong Wang ret = register_pernet_subsys(&pg_net_ops); 39674e58a027SCong Wang if (ret) 39684e58a027SCong Wang return ret; 39694e58a027SCong Wang ret = register_netdevice_notifier(&pktgen_notifier_block); 39704e58a027SCong Wang if (ret) 39714e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 39724e58a027SCong Wang 39734e58a027SCong Wang return ret; 39744e58a027SCong Wang } 39754e58a027SCong Wang 39764e58a027SCong Wang static void __exit pg_cleanup(void) 39774e58a027SCong Wang { 39784e58a027SCong Wang unregister_netdevice_notifier(&pktgen_notifier_block); 39794e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 39808788370aSJesper Dangaard Brouer /* Don't need rcu_barrier() due to use of kfree_rcu() */ 39811da177e4SLinus Torvalds } 39821da177e4SLinus Torvalds 39831da177e4SLinus Torvalds module_init(pg_init); 39841da177e4SLinus Torvalds module_exit(pg_cleanup); 39851da177e4SLinus Torvalds 3986c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 39871da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 39881da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3989c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 39901da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3991c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 39921da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3993c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 39941da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3995c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 39961da177e4SLinus Torvalds module_param(debug, int, 0); 3997c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3998