12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Authors: 41da177e4SLinus Torvalds * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> 51da177e4SLinus Torvalds * Uppsala University and 61da177e4SLinus Torvalds * Swedish University of Agricultural Sciences 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 91da177e4SLinus Torvalds * Ben Greear <greearb@candelatech.com> 1096de0e25SJan Engelhardt * Jens Låås <jens.laas@data.slu.se> 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * A tool for loading the network with preconfigurated packets. 131da177e4SLinus Torvalds * The tool is implemented as a linux module. Parameters are output 141da177e4SLinus Torvalds * device, delay (to hard_xmit), number of packets, and whether 151da177e4SLinus Torvalds * to use multiple SKBs or just the same one. 161da177e4SLinus Torvalds * pktgen uses the installed interface's output routine. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * Additional hacking by: 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * Jens.Laas@data.slu.se 211da177e4SLinus Torvalds * Improved by ANK. 010120. 221da177e4SLinus Torvalds * Improved by ANK even more. 010212. 231da177e4SLinus Torvalds * MAC address typo fixed. 010417 --ro 241da177e4SLinus Torvalds * Integrated. 020301 --DaveM 251da177e4SLinus Torvalds * Added multiskb option 020301 --DaveM 261da177e4SLinus Torvalds * Scaling of results. 020417--sigurdur@linpro.no 271da177e4SLinus Torvalds * Significant re-work of the module: 281da177e4SLinus Torvalds * * Convert to threaded model to more efficiently be able to transmit 291da177e4SLinus Torvalds * and receive on multiple interfaces at once. 301da177e4SLinus Torvalds * * Converted many counters to __u64 to allow longer runs. 311da177e4SLinus Torvalds * * Allow configuration of ranges, like min/max IP address, MACs, 321da177e4SLinus Torvalds * and UDP-ports, for both source and destination, and can 331da177e4SLinus Torvalds * set to use a random distribution or sequentially walk the range. 341da177e4SLinus Torvalds * * Can now change most values after starting. 351da177e4SLinus Torvalds * * Place 12-byte packet in UDP payload with magic number, 361da177e4SLinus Torvalds * sequence number, and timestamp. 371da177e4SLinus Torvalds * * Add receiver code that detects dropped pkts, re-ordered pkts, and 381da177e4SLinus Torvalds * latencies (with micro-second) precision. 391da177e4SLinus Torvalds * * Add IOCTL interface to easily get counters & configuration. 401da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 411da177e4SLinus Torvalds * 421da177e4SLinus Torvalds * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 431da177e4SLinus Torvalds * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 441da177e4SLinus Torvalds * as a "fastpath" with a configurable number of clones after alloc's. 451da177e4SLinus Torvalds * clone_skb=0 means all packets are allocated this also means ranges time 461da177e4SLinus Torvalds * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 471da177e4SLinus Torvalds * clones. 481da177e4SLinus Torvalds * 491da177e4SLinus Torvalds * Also moved to /proc/net/pktgen/ 501da177e4SLinus Torvalds * --ro 511da177e4SLinus Torvalds * 521da177e4SLinus Torvalds * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever 531da177e4SLinus Torvalds * mistakes. Also merged in DaveM's patch in the -pre6 patch. 541da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 551da177e4SLinus Torvalds * 561da177e4SLinus Torvalds * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) 571da177e4SLinus Torvalds * 581da177e4SLinus Torvalds * 021124 Finished major redesign and rewrite for new functionality. 59c1e4535fSMauro Carvalho Chehab * See Documentation/networking/pktgen.rst for how to use this. 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * The new operation: 621da177e4SLinus Torvalds * For each CPU one thread/process is created at start. This process checks 631da177e4SLinus Torvalds * for running devices in the if_list and sends packets until count is 0 it 641da177e4SLinus Torvalds * also the thread checks the thread->control which is used for inter-process 651da177e4SLinus Torvalds * communication. controlling process "posts" operations to the threads this 668788370aSJesper Dangaard Brouer * way. 678788370aSJesper Dangaard Brouer * The if_list is RCU protected, and the if_lock remains to protect updating 688788370aSJesper Dangaard Brouer * of if_list, from "add_device" as it invoked from userspace (via proc write). 691da177e4SLinus Torvalds * 701da177e4SLinus Torvalds * By design there should only be *one* "controlling" process. In practice 711da177e4SLinus Torvalds * multiple write accesses gives unpredictable result. Understood by "write" 721da177e4SLinus Torvalds * to /proc gives result code thats should be read be the "writer". 73b4099fabSStephen Hemminger * For practical use this should be no problem. 741da177e4SLinus Torvalds * 751da177e4SLinus Torvalds * Note when adding devices to a specific CPU there good idea to also assign 761da177e4SLinus Torvalds * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 771da177e4SLinus Torvalds * --ro 781da177e4SLinus Torvalds * 791da177e4SLinus Torvalds * Fix refcount off by one if first packet fails, potential null deref, 801da177e4SLinus Torvalds * memleak 030710- KJP 811da177e4SLinus Torvalds * 821da177e4SLinus Torvalds * First "ranges" functionality for ipv6 030726 --ro 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * Included flow support. 030802 ANK. 851da177e4SLinus Torvalds * 861da177e4SLinus Torvalds * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> 871da177e4SLinus Torvalds * 881da177e4SLinus Torvalds * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 891da177e4SLinus Torvalds * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 901da177e4SLinus Torvalds * 911da177e4SLinus Torvalds * New xmit() return, do_div and misc clean up by Stephen Hemminger 921da177e4SLinus Torvalds * <shemminger@osdl.org> 040923 931da177e4SLinus Torvalds * 94ca9f1fd2SStephen Hemminger * Randy Dunlap fixed u64 printk compiler warning 951da177e4SLinus Torvalds * 961da177e4SLinus Torvalds * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> 971da177e4SLinus Torvalds * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 981da177e4SLinus Torvalds * 991da177e4SLinus Torvalds * Corrections from Nikolai Malykh (nmalykh@bilim.com) 1001da177e4SLinus Torvalds * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 1011da177e4SLinus Torvalds * 1021da177e4SLinus Torvalds * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 1031da177e4SLinus Torvalds * 050103 104ca6549afSSteven Whitehouse * 105ca6549afSSteven Whitehouse * MPLS support by Steven Whitehouse <steve@chygwyn.com> 106ca6549afSSteven Whitehouse * 10734954ddcSFrancesco Fondelli * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> 10834954ddcSFrancesco Fondelli * 109ce5d0b47SAdit Ranadive * Fixed src_mac command to set source mac of packet to value specified in 110ce5d0b47SAdit Ranadive * command by Adit Ranadive <adit.262@gmail.com> 1111da177e4SLinus Torvalds */ 112f9467eaeSJoe Perches 113f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 114f9467eaeSJoe Perches 1151da177e4SLinus Torvalds #include <linux/sys.h> 1161da177e4SLinus Torvalds #include <linux/types.h> 1171da177e4SLinus Torvalds #include <linux/module.h> 1181da177e4SLinus Torvalds #include <linux/moduleparam.h> 1191da177e4SLinus Torvalds #include <linux/kernel.h> 120222fa076SLuiz Capitulino #include <linux/mutex.h> 1211da177e4SLinus Torvalds #include <linux/sched.h> 1221da177e4SLinus Torvalds #include <linux/slab.h> 1231da177e4SLinus Torvalds #include <linux/vmalloc.h> 1241da177e4SLinus Torvalds #include <linux/unistd.h> 1251da177e4SLinus Torvalds #include <linux/string.h> 1261da177e4SLinus Torvalds #include <linux/ptrace.h> 1271da177e4SLinus Torvalds #include <linux/errno.h> 1281da177e4SLinus Torvalds #include <linux/ioport.h> 1291da177e4SLinus Torvalds #include <linux/interrupt.h> 1304fc268d2SRandy Dunlap #include <linux/capability.h> 1312bc481cfSStephen Hemminger #include <linux/hrtimer.h> 13209fe3ef4SAndrew Morton #include <linux/freezer.h> 1331da177e4SLinus Torvalds #include <linux/delay.h> 1341da177e4SLinus Torvalds #include <linux/timer.h> 135cdcdbe0bSLuiz Capitulino #include <linux/list.h> 1361da177e4SLinus Torvalds #include <linux/init.h> 1371da177e4SLinus Torvalds #include <linux/skbuff.h> 1381da177e4SLinus Torvalds #include <linux/netdevice.h> 1391da177e4SLinus Torvalds #include <linux/inet.h> 1401da177e4SLinus Torvalds #include <linux/inetdevice.h> 1411da177e4SLinus Torvalds #include <linux/rtnetlink.h> 1421da177e4SLinus Torvalds #include <linux/if_arp.h> 14334954ddcSFrancesco Fondelli #include <linux/if_vlan.h> 1441da177e4SLinus Torvalds #include <linux/in.h> 1451da177e4SLinus Torvalds #include <linux/ip.h> 1461da177e4SLinus Torvalds #include <linux/ipv6.h> 1471da177e4SLinus Torvalds #include <linux/udp.h> 1481da177e4SLinus Torvalds #include <linux/proc_fs.h> 149d50a6b56SStephen Hemminger #include <linux/seq_file.h> 1501da177e4SLinus Torvalds #include <linux/wait.h> 151f404e9a6SKris Katterjohn #include <linux/etherdevice.h> 152ee74baa7SDavid S. Miller #include <linux/kthread.h> 153268bb0ceSLinus Torvalds #include <linux/prefetch.h> 15498fa15f3SAnshuman Khandual #include <linux/mmzone.h> 155457c4cbcSEric W. Biederman #include <net/net_namespace.h> 1561da177e4SLinus Torvalds #include <net/checksum.h> 1571da177e4SLinus Torvalds #include <net/ipv6.h> 158c26bf4a5SThomas Graf #include <net/udp.h> 15973d94e94SStephen Rothwell #include <net/ip6_checksum.h> 1601da177e4SLinus Torvalds #include <net/addrconf.h> 161a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 162a553e4a6SJamal Hadi Salim #include <net/xfrm.h> 163a553e4a6SJamal Hadi Salim #endif 1644e58a027SCong Wang #include <net/netns/generic.h> 1651da177e4SLinus Torvalds #include <asm/byteorder.h> 1661da177e4SLinus Torvalds #include <linux/rcupdate.h> 1671977f032SJiri Slaby #include <linux/bitops.h> 16863adc6fbSStephen Hemminger #include <linux/io.h> 16963adc6fbSStephen Hemminger #include <linux/timex.h> 17063adc6fbSStephen Hemminger #include <linux/uaccess.h> 1711da177e4SLinus Torvalds #include <asm/dma.h> 1721da177e4SLinus Torvalds #include <asm/div64.h> /* do_div */ 1731da177e4SLinus Torvalds 17440207264SJesper Dangaard Brouer #define VERSION "2.75" 1751da177e4SLinus Torvalds #define IP_NAME_SZ 32 176ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ 177d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100) 17852a62f86SNick Richardson /* Max number of internet mix entries that can be specified in imix_weights. */ 17952a62f86SNick Richardson #define MAX_IMIX_ENTRIES 20 18090149031SNick Richardson #define IMIX_PRECISION 100 /* Precision of IMIX distribution */ 1811da177e4SLinus Torvalds 182f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__); 183f9467eaeSJoe Perches 1846f107c74SDmitry Safonov #define PKT_FLAGS \ 1856f107c74SDmitry Safonov pf(IPV6) /* Interface in IPV6 Mode */ \ 1866f107c74SDmitry Safonov pf(IPSRC_RND) /* IP-Src Random */ \ 1876f107c74SDmitry Safonov pf(IPDST_RND) /* IP-Dst Random */ \ 1886f107c74SDmitry Safonov pf(TXSIZE_RND) /* Transmit size is random */ \ 1896f107c74SDmitry Safonov pf(UDPSRC_RND) /* UDP-Src Random */ \ 1906f107c74SDmitry Safonov pf(UDPDST_RND) /* UDP-Dst Random */ \ 1916f107c74SDmitry Safonov pf(UDPCSUM) /* Include UDP checksum */ \ 1926f107c74SDmitry Safonov pf(NO_TIMESTAMP) /* Don't timestamp packets (default TS) */ \ 1936f107c74SDmitry Safonov pf(MPLS_RND) /* Random MPLS labels */ \ 1946f107c74SDmitry Safonov pf(QUEUE_MAP_RND) /* queue map Random */ \ 1956f107c74SDmitry Safonov pf(QUEUE_MAP_CPU) /* queue map mirrors smp_processor_id() */ \ 1966f107c74SDmitry Safonov pf(FLOW_SEQ) /* Sequential flows */ \ 1976f107c74SDmitry Safonov pf(IPSEC) /* ipsec on for flows */ \ 1986f107c74SDmitry Safonov pf(MACSRC_RND) /* MAC-Src Random */ \ 1996f107c74SDmitry Safonov pf(MACDST_RND) /* MAC-Dst Random */ \ 2006f107c74SDmitry Safonov pf(VID_RND) /* Random VLAN ID */ \ 2016f107c74SDmitry Safonov pf(SVID_RND) /* Random SVLAN ID */ \ 2026f107c74SDmitry Safonov pf(NODE) /* Node memory alloc*/ \ 2036f107c74SDmitry Safonov 2046f107c74SDmitry Safonov #define pf(flag) flag##_SHIFT, 2056f107c74SDmitry Safonov enum pkt_flags { 2066f107c74SDmitry Safonov PKT_FLAGS 2076f107c74SDmitry Safonov }; 2086f107c74SDmitry Safonov #undef pf 2096f107c74SDmitry Safonov 2101da177e4SLinus Torvalds /* Device flag bits */ 2116f107c74SDmitry Safonov #define pf(flag) static const __u32 F_##flag = (1<<flag##_SHIFT); 2126f107c74SDmitry Safonov PKT_FLAGS 2136f107c74SDmitry Safonov #undef pf 2141da177e4SLinus Torvalds 21599c6d3d2SDmitry Safonov #define pf(flag) __stringify(flag), 21699c6d3d2SDmitry Safonov static char *pkt_flag_names[] = { 21799c6d3d2SDmitry Safonov PKT_FLAGS 21899c6d3d2SDmitry Safonov }; 21999c6d3d2SDmitry Safonov #undef pf 22099c6d3d2SDmitry Safonov 22199c6d3d2SDmitry Safonov #define NR_PKT_FLAGS ARRAY_SIZE(pkt_flag_names) 22299c6d3d2SDmitry Safonov 2231da177e4SLinus Torvalds /* Thread control flag bits */ 2246b80d6a6SStephen Hemminger #define T_STOP (1<<0) /* Stop run */ 2256b80d6a6SStephen Hemminger #define T_RUN (1<<1) /* Start run */ 2266b80d6a6SStephen Hemminger #define T_REMDEVALL (1<<2) /* Remove all devs */ 2276b80d6a6SStephen Hemminger #define T_REMDEV (1<<3) /* Remove one dev */ 2281da177e4SLinus Torvalds 22962f64aedSAlexei Starovoitov /* Xmit modes */ 23062f64aedSAlexei Starovoitov #define M_START_XMIT 0 /* Default normal TX */ 23162f64aedSAlexei Starovoitov #define M_NETIF_RECEIVE 1 /* Inject packets into stack */ 2320967f244SJohn Fastabend #define M_QUEUE_XMIT 2 /* Inject packet into qdisc */ 23362f64aedSAlexei Starovoitov 2348788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */ 2359a0b1e8bSEric Dumazet #define if_lock(t) mutex_lock(&(t->if_lock)); 2369a0b1e8bSEric Dumazet #define if_unlock(t) mutex_unlock(&(t->if_lock)); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 2391da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 240d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen" 241d50a6b56SStephen Hemminger #define PGCTRL "pgctrl" 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds #define MAX_CFLOWS 65536 2441da177e4SLinus Torvalds 24534954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 24634954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 24734954ddcSFrancesco Fondelli 24852a62f86SNick Richardson struct imix_pkt { 24952a62f86SNick Richardson u64 size; 25052a62f86SNick Richardson u64 weight; 25152a62f86SNick Richardson u64 count_so_far; 25252a62f86SNick Richardson }; 25352a62f86SNick Richardson 254222f1806SLuiz Capitulino struct flow_state { 255252e3346SAl Viro __be32 cur_daddr; 2561da177e4SLinus Torvalds int count; 257a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 258a553e4a6SJamal Hadi Salim struct xfrm_state *x; 259a553e4a6SJamal Hadi Salim #endif 260007a531bSJamal Hadi Salim __u32 flags; 2611da177e4SLinus Torvalds }; 2621da177e4SLinus Torvalds 263007a531bSJamal Hadi Salim /* flow flag bits */ 264007a531bSJamal Hadi Salim #define F_INIT (1<<0) /* flow has been initialized */ 265007a531bSJamal Hadi Salim 2661da177e4SLinus Torvalds struct pktgen_dev { 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 2691da177e4SLinus Torvalds */ 27039df232fSStephen Hemminger struct proc_dir_entry *entry; /* proc file */ 2711da177e4SLinus Torvalds struct pktgen_thread *pg_thread;/* the owner */ 27263adc6fbSStephen Hemminger struct list_head list; /* chaining in the thread's run-queue */ 2738788370aSJesper Dangaard Brouer struct rcu_head rcu; /* freed by RCU */ 2741da177e4SLinus Torvalds 27563adc6fbSStephen Hemminger int running; /* if false, the test will stop */ 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 2781da177e4SLinus Torvalds * we will do a random selection from within the range. 2791da177e4SLinus Torvalds */ 2801da177e4SLinus Torvalds __u32 flags; 28162f64aedSAlexei Starovoitov int xmit_mode; 28268bf9f0bSAmerigo Wang int min_pkt_size; 28368bf9f0bSAmerigo Wang int max_pkt_size; 28416dab72fSJamal Hadi Salim int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2851da177e4SLinus Torvalds int nfrags; 28662f64aedSAlexei Starovoitov int removal_mark; /* non-zero => the device is marked for 28762f64aedSAlexei Starovoitov * removal by worker thread */ 28862f64aedSAlexei Starovoitov 28926ad7879SEric Dumazet struct page *page; 290fd29cf72SStephen Hemminger u64 delay; /* nano-seconds */ 291fd29cf72SStephen Hemminger 2921da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 2931da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 2941da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 295f466dba1SJohn Fastabend __u64 errors; /* Errors when trying to transmit, */ 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds __u32 clone_count; 3001da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 30163adc6fbSStephen Hemminger * Or a failed transmit of some sort? 30263adc6fbSStephen Hemminger * This will keep sequence numbers in order 3031da177e4SLinus Torvalds */ 304fd29cf72SStephen Hemminger ktime_t next_tx; 305fd29cf72SStephen Hemminger ktime_t started_at; 306fd29cf72SStephen Hemminger ktime_t stopped_at; 307fd29cf72SStephen Hemminger u64 idle_acc; /* nano-seconds */ 308fd29cf72SStephen Hemminger 3091da177e4SLinus Torvalds __u32 seq_num; 3101da177e4SLinus Torvalds 31163adc6fbSStephen Hemminger int clone_skb; /* 31263adc6fbSStephen Hemminger * Use multiple SKBs during packet gen. 31363adc6fbSStephen Hemminger * If this number is greater than 1, then 31463adc6fbSStephen Hemminger * that many copies of the same packet will be 31563adc6fbSStephen Hemminger * sent before a new packet is allocated. 31663adc6fbSStephen Hemminger * If you want to send 1024 identical packets 31763adc6fbSStephen Hemminger * before creating a new packet, 31863adc6fbSStephen Hemminger * set clone_skb to 1024. 3191da177e4SLinus Torvalds */ 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3221da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3231da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3241da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds struct in6_addr in6_saddr; 3271da177e4SLinus Torvalds struct in6_addr in6_daddr; 3281da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 3291da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 3301da177e4SLinus Torvalds /* For ranges */ 3311da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 3321da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 3331da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 3341da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 3371da177e4SLinus Torvalds * defines the min/max for those ranges. 3381da177e4SLinus Torvalds */ 339252e3346SAl Viro __be32 saddr_min; /* inclusive, source IP address */ 340252e3346SAl Viro __be32 saddr_max; /* exclusive, source IP address */ 341252e3346SAl Viro __be32 daddr_min; /* inclusive, dest IP address */ 342252e3346SAl Viro __be32 daddr_max; /* exclusive, dest IP address */ 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 3451da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 3461da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 3471da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 3481da177e4SLinus Torvalds 3491ca7768cSFrancesco Fondelli /* DSCP + ECN */ 35063adc6fbSStephen Hemminger __u8 tos; /* six MSB of (former) IPv4 TOS 35163adc6fbSStephen Hemminger are for dscp codepoint */ 35263adc6fbSStephen Hemminger __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 35363adc6fbSStephen Hemminger (see RFC 3260, sec. 4) */ 3541ca7768cSFrancesco Fondelli 35552a62f86SNick Richardson /* IMIX */ 35652a62f86SNick Richardson unsigned int n_imix_entries; 35752a62f86SNick Richardson struct imix_pkt imix_entries[MAX_IMIX_ENTRIES]; 35890149031SNick Richardson /* Maps 0-IMIX_PRECISION range to imix_entry based on probability*/ 35990149031SNick Richardson __u8 imix_distribution[IMIX_PRECISION]; 36052a62f86SNick Richardson 361ca6549afSSteven Whitehouse /* MPLS */ 36295c96174SEric Dumazet unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */ 363ca6549afSSteven Whitehouse __be32 labels[MAX_MPLS_LABELS]; 364ca6549afSSteven Whitehouse 36534954ddcSFrancesco Fondelli /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 36634954ddcSFrancesco Fondelli __u8 vlan_p; 36734954ddcSFrancesco Fondelli __u8 vlan_cfi; 36834954ddcSFrancesco Fondelli __u16 vlan_id; /* 0xffff means no vlan tag */ 36934954ddcSFrancesco Fondelli 37034954ddcSFrancesco Fondelli __u8 svlan_p; 37134954ddcSFrancesco Fondelli __u8 svlan_cfi; 37234954ddcSFrancesco Fondelli __u16 svlan_id; /* 0xffff means no svlan tag */ 37334954ddcSFrancesco Fondelli 3741da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 3751da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 3761da177e4SLinus Torvalds 377f404e9a6SKris Katterjohn unsigned char dst_mac[ETH_ALEN]; 378f404e9a6SKris Katterjohn unsigned char src_mac[ETH_ALEN]; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 3811da177e4SLinus Torvalds __u32 cur_src_mac_offset; 382252e3346SAl Viro __be32 cur_saddr; 383252e3346SAl Viro __be32 cur_daddr; 38466ed1e5eSEric Dumazet __u16 ip_id; 3851da177e4SLinus Torvalds __u16 cur_udp_dst; 3861da177e4SLinus Torvalds __u16 cur_udp_src; 38745b270f8SRobert Olsson __u16 cur_queue_map; 3881da177e4SLinus Torvalds __u32 cur_pkt_size; 389baac8564SEric Dumazet __u32 last_pkt_size; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds __u8 hh[14]; 3921da177e4SLinus Torvalds /* = { 3931da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds We fill in SRC address later 3961da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3971da177e4SLinus Torvalds 0x08, 0x00 3981da177e4SLinus Torvalds }; 3991da177e4SLinus Torvalds */ 4001da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 4011da177e4SLinus Torvalds 40263adc6fbSStephen Hemminger struct sk_buff *skb; /* skb we are to transmit next, used for when we 4031da177e4SLinus Torvalds * are transmitting the same one multiple times 4041da177e4SLinus Torvalds */ 40563adc6fbSStephen Hemminger struct net_device *odev; /* The out-going device. 40663adc6fbSStephen Hemminger * Note that the device should have it's 40763adc6fbSStephen Hemminger * pg_info pointer pointing back to this 40863adc6fbSStephen Hemminger * device. 40963adc6fbSStephen Hemminger * Set when the user specifies the out-going 41063adc6fbSStephen Hemminger * device name (not when the inject is 4111da177e4SLinus Torvalds * started as it used to do.) 4121da177e4SLinus Torvalds */ 413035f1f2bSEric Dumazet netdevice_tracker dev_tracker; 414593f63b0SEric Dumazet char odevname[32]; 4151da177e4SLinus Torvalds struct flow_state *flows; 41695c96174SEric Dumazet unsigned int cflows; /* Concurrent flows (config) */ 41795c96174SEric Dumazet unsigned int lflow; /* Flow length (config) */ 41895c96174SEric Dumazet unsigned int nflows; /* accumulated flows (stats) */ 41995c96174SEric Dumazet unsigned int curfl; /* current sequenced flow (state)*/ 42045b270f8SRobert Olsson 42145b270f8SRobert Olsson u16 queue_map_min; 42245b270f8SRobert Olsson u16 queue_map_max; 4239e50e3acSJohn Fastabend __u32 skb_priority; /* skb priority field */ 42438b2cf29SAlexei Starovoitov unsigned int burst; /* number of duplicated packets to burst */ 425e99b99b4SRobert Olsson int node; /* Memory node */ 42645b270f8SRobert Olsson 427a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 428a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 429a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 430de4aee7dSFan Du __u32 spi; 431b6ca8bd5SDavid Miller struct xfrm_dst xdst; 432cf93d47eSFan Du struct dst_ops dstops; 433a553e4a6SJamal Hadi Salim #endif 43439df232fSStephen Hemminger char result[512]; 4351da177e4SLinus Torvalds }; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds struct pktgen_hdr { 438252e3346SAl Viro __be32 pgh_magic; 439252e3346SAl Viro __be32 seq_num; 440252e3346SAl Viro __be32 tv_sec; 441252e3346SAl Viro __be32 tv_usec; 4421da177e4SLinus Torvalds }; 4431da177e4SLinus Torvalds 4444e58a027SCong Wang 445c7d03a00SAlexey Dobriyan static unsigned int pg_net_id __read_mostly; 4464e58a027SCong Wang 4474e58a027SCong Wang struct pktgen_net { 4484e58a027SCong Wang struct net *net; 4494e58a027SCong Wang struct proc_dir_entry *proc_dir; 4504e58a027SCong Wang struct list_head pktgen_threads; 4514e58a027SCong Wang bool pktgen_exiting; 4524e58a027SCong Wang }; 453551eaff1SEric Dumazet 4541da177e4SLinus Torvalds struct pktgen_thread { 4559a0b1e8bSEric Dumazet struct mutex if_lock; /* for list of devices */ 456c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 457cdcdbe0bSLuiz Capitulino struct list_head th_list; 458ee74baa7SDavid S. Miller struct task_struct *tsk; 4591da177e4SLinus Torvalds char result[512]; 4601da177e4SLinus Torvalds 46163adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 46263adc6fbSStephen Hemminger stop ifs etc. */ 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds u32 control; 4651da177e4SLinus Torvalds int cpu; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds wait_queue_head_t queue; 468d3ede327SDenis V. Lunev struct completion start_done; 4694e58a027SCong Wang struct pktgen_net *net; 4701da177e4SLinus Torvalds }; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds #define REMOVE 1 4731da177e4SLinus Torvalds #define FIND 0 4741da177e4SLinus Torvalds 475c3d2f52dSStephen Hemminger static const char version[] = 476f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 477f9467eaeSJoe Perches "Version: " VERSION "\n"; 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4801da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 481222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4823e984840SEric Dumazet const char *ifname, bool exact); 4831da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4844e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn); 4854e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn); 486cda9de0bSYejune Deng static void pktgen_stop_all_threads(struct pktgen_net *pn); 4873bda06a3SStephen Hemminger 4881da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4891da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 49090149031SNick Richardson static void fill_imix_distribution(struct pktgen_dev *pkt_dev); 49139df232fSStephen Hemminger 4921da177e4SLinus Torvalds /* Module parameters, defaults. */ 49365c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 49465c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 49565c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 49665c5b786SStephen Hemminger static int debug __read_mostly; 4971da177e4SLinus Torvalds 498222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 5011da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 5021da177e4SLinus Torvalds }; 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds /* 5051da177e4SLinus Torvalds * /proc handling functions 5061da177e4SLinus Torvalds * 5071da177e4SLinus Torvalds */ 5081da177e4SLinus Torvalds 509d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 510d50a6b56SStephen Hemminger { 511c3d2f52dSStephen Hemminger seq_puts(seq, version); 512d50a6b56SStephen Hemminger return 0; 513d50a6b56SStephen Hemminger } 5141da177e4SLinus Torvalds 515d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 5161da177e4SLinus Torvalds size_t count, loff_t *ppos) 5171da177e4SLinus Torvalds { 518d50a6b56SStephen Hemminger char data[128]; 5194e58a027SCong Wang struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id); 5201da177e4SLinus Torvalds 52109455747SMathias Krause if (!capable(CAP_NET_ADMIN)) 52209455747SMathias Krause return -EPERM; 5231da177e4SLinus Torvalds 52420b0c718SMathias Krause if (count == 0) 52520b0c718SMathias Krause return -EINVAL; 52620b0c718SMathias Krause 527d50a6b56SStephen Hemminger if (count > sizeof(data)) 528d50a6b56SStephen Hemminger count = sizeof(data); 5291da177e4SLinus Torvalds 53009455747SMathias Krause if (copy_from_user(data, buf, count)) 53109455747SMathias Krause return -EFAULT; 53209455747SMathias Krause 53320b0c718SMathias Krause data[count - 1] = 0; /* Strip trailing '\n' and terminate string */ 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds if (!strcmp(data, "stop")) 536cda9de0bSYejune Deng pktgen_stop_all_threads(pn); 5371da177e4SLinus Torvalds else if (!strcmp(data, "start")) 5384e58a027SCong Wang pktgen_run_all_threads(pn); 539eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 5404e58a027SCong Wang pktgen_reset_all_threads(pn); 5411da177e4SLinus Torvalds else 54240207264SJesper Dangaard Brouer return -EINVAL; 5431da177e4SLinus Torvalds 54409455747SMathias Krause return count; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 547d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5481da177e4SLinus Torvalds { 549*359745d7SMuchun Song return single_open(file, pgctrl_show, pde_data(inode)); 550d50a6b56SStephen Hemminger } 551d50a6b56SStephen Hemminger 55297a32539SAlexey Dobriyan static const struct proc_ops pktgen_proc_ops = { 55397a32539SAlexey Dobriyan .proc_open = pgctrl_open, 55497a32539SAlexey Dobriyan .proc_read = seq_read, 55597a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 55697a32539SAlexey Dobriyan .proc_write = pgctrl_write, 55797a32539SAlexey Dobriyan .proc_release = single_release, 558d50a6b56SStephen Hemminger }; 559d50a6b56SStephen Hemminger 560d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 561d50a6b56SStephen Hemminger { 562648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 563fd29cf72SStephen Hemminger ktime_t stopped; 56499c6d3d2SDmitry Safonov unsigned int i; 565fd29cf72SStephen Hemminger u64 idle; 5661da177e4SLinus Torvalds 567222f1806SLuiz Capitulino seq_printf(seq, 568222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 569222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 570222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5711da177e4SLinus Torvalds 57252a62f86SNick Richardson if (pkt_dev->n_imix_entries > 0) { 57352a62f86SNick Richardson seq_puts(seq, " imix_weights: "); 57452a62f86SNick Richardson for (i = 0; i < pkt_dev->n_imix_entries; i++) { 57552a62f86SNick Richardson seq_printf(seq, "%llu,%llu ", 57652a62f86SNick Richardson pkt_dev->imix_entries[i].size, 57752a62f86SNick Richardson pkt_dev->imix_entries[i].weight); 57852a62f86SNick Richardson } 57952a62f86SNick Richardson seq_puts(seq, "\n"); 58052a62f86SNick Richardson } 58152a62f86SNick Richardson 582222f1806SLuiz Capitulino seq_printf(seq, 583fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 584fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 585593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5861da177e4SLinus Torvalds 587222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 588222f1806SLuiz Capitulino pkt_dev->lflow); 5891da177e4SLinus Torvalds 59045b270f8SRobert Olsson seq_printf(seq, 59145b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 59245b270f8SRobert Olsson pkt_dev->queue_map_min, 59345b270f8SRobert Olsson pkt_dev->queue_map_max); 59445b270f8SRobert Olsson 5959e50e3acSJohn Fastabend if (pkt_dev->skb_priority) 5969e50e3acSJohn Fastabend seq_printf(seq, " skb_priority: %u\n", 5979e50e3acSJohn Fastabend pkt_dev->skb_priority); 5989e50e3acSJohn Fastabend 5991da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 600222f1806SLuiz Capitulino seq_printf(seq, 60147a0200dSAlexey Dobriyan " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" 60247a0200dSAlexey Dobriyan " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", 60347a0200dSAlexey Dobriyan &pkt_dev->in6_saddr, 60447a0200dSAlexey Dobriyan &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, 60547a0200dSAlexey Dobriyan &pkt_dev->in6_daddr, 60647a0200dSAlexey Dobriyan &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); 60763adc6fbSStephen Hemminger } else { 608222f1806SLuiz Capitulino seq_printf(seq, 60963adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 61063adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 61163adc6fbSStephen Hemminger seq_printf(seq, 61263adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 61363adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 61463adc6fbSStephen Hemminger } 6151da177e4SLinus Torvalds 616d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 6171da177e4SLinus Torvalds 618e174961cSJohannes Berg seq_printf(seq, "%pM ", 619e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 620e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 6211da177e4SLinus Torvalds 62297dc48e2SThomas Graf seq_puts(seq, "dst_mac: "); 623e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 6241da177e4SLinus Torvalds 625222f1806SLuiz Capitulino seq_printf(seq, 62663adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 62763adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 628222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 629222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 6301da177e4SLinus Torvalds 631222f1806SLuiz Capitulino seq_printf(seq, 632ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 6331da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 6341da177e4SLinus Torvalds 635ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 63697dc48e2SThomas Graf seq_puts(seq, " mpls: "); 637ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 638ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 639ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 640ca6549afSSteven Whitehouse } 641ca6549afSSteven Whitehouse 64263adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 64334954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 64463adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 64563adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 64634954ddcSFrancesco Fondelli 64763adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 64834954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 64963adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 65063adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 65134954ddcSFrancesco Fondelli 65263adc6fbSStephen Hemminger if (pkt_dev->tos) 6531ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6541ca7768cSFrancesco Fondelli 65563adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6561ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6571ca7768cSFrancesco Fondelli 65838b2cf29SAlexei Starovoitov if (pkt_dev->burst > 1) 65938b2cf29SAlexei Starovoitov seq_printf(seq, " burst: %d\n", pkt_dev->burst); 66038b2cf29SAlexei Starovoitov 661e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 662e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 663e99b99b4SRobert Olsson 66462f64aedSAlexei Starovoitov if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) 66562f64aedSAlexei Starovoitov seq_puts(seq, " xmit_mode: netif_receive\n"); 6660967f244SJohn Fastabend else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) 6670967f244SJohn Fastabend seq_puts(seq, " xmit_mode: xmit_queue\n"); 66862f64aedSAlexei Starovoitov 66997dc48e2SThomas Graf seq_puts(seq, " Flags: "); 670ca6549afSSteven Whitehouse 67199c6d3d2SDmitry Safonov for (i = 0; i < NR_PKT_FLAGS; i++) { 67299c6d3d2SDmitry Safonov if (i == F_FLOW_SEQ) 67399c6d3d2SDmitry Safonov if (!pkt_dev->cflows) 67499c6d3d2SDmitry Safonov continue; 6751da177e4SLinus Torvalds 67699c6d3d2SDmitry Safonov if (pkt_dev->flags & (1 << i)) 67799c6d3d2SDmitry Safonov seq_printf(seq, "%s ", pkt_flag_names[i]); 67899c6d3d2SDmitry Safonov else if (i == F_FLOW_SEQ) 67997dc48e2SThomas Graf seq_puts(seq, "FLOW_RND "); 680007a531bSJamal Hadi Salim 681a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 68299c6d3d2SDmitry Safonov if (i == F_IPSEC && pkt_dev->spi) 6838101328bSFan Du seq_printf(seq, "spi:%u", pkt_dev->spi); 684a553e4a6SJamal Hadi Salim #endif 68599c6d3d2SDmitry Safonov } 686e99b99b4SRobert Olsson 687d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 6881da177e4SLinus Torvalds 689fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 690398f382cSDaniel Borkmann stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at; 691fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 692fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 6931da177e4SLinus Torvalds 694222f1806SLuiz Capitulino seq_printf(seq, 695fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 6961da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 697fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 698fd29cf72SStephen Hemminger 699769afb3fSNick Richardson if (pkt_dev->n_imix_entries > 0) { 700769afb3fSNick Richardson int i; 701769afb3fSNick Richardson 702769afb3fSNick Richardson seq_puts(seq, " imix_size_counts: "); 703769afb3fSNick Richardson for (i = 0; i < pkt_dev->n_imix_entries; i++) { 704769afb3fSNick Richardson seq_printf(seq, "%llu,%llu ", 705769afb3fSNick Richardson pkt_dev->imix_entries[i].size, 706769afb3fSNick Richardson pkt_dev->imix_entries[i].count_so_far); 707769afb3fSNick Richardson } 708769afb3fSNick Richardson seq_puts(seq, "\n"); 709769afb3fSNick Richardson } 710769afb3fSNick Richardson 711fd29cf72SStephen Hemminger seq_printf(seq, 712fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 713fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 714fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 715fd29cf72SStephen Hemminger (unsigned long long) idle); 7161da177e4SLinus Torvalds 717222f1806SLuiz Capitulino seq_printf(seq, 718222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 719d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 720d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 72347a0200dSAlexey Dobriyan seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", 72447a0200dSAlexey Dobriyan &pkt_dev->cur_in6_saddr, 72547a0200dSAlexey Dobriyan &pkt_dev->cur_in6_daddr); 726222f1806SLuiz Capitulino } else 7270373a946SAmerigo Wang seq_printf(seq, " cur_saddr: %pI4 cur_daddr: %pI4\n", 7280373a946SAmerigo Wang &pkt_dev->cur_saddr, &pkt_dev->cur_daddr); 7291da177e4SLinus Torvalds 730d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7311da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7321da177e4SLinus Torvalds 73345b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 73445b270f8SRobert Olsson 735d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds if (pkt_dev->result[0]) 738d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7391da177e4SLinus Torvalds else 74097dc48e2SThomas Graf seq_puts(seq, "Result: Idle\n"); 7411da177e4SLinus Torvalds 742d50a6b56SStephen Hemminger return 0; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds 745ca6549afSSteven Whitehouse 74663adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 74763adc6fbSStephen Hemminger __u32 *num) 748ca6549afSSteven Whitehouse { 749ca6549afSSteven Whitehouse int i = 0; 750ca6549afSSteven Whitehouse *num = 0; 751ca6549afSSteven Whitehouse 7521ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 75382fd5b5dSAndy Shevchenko int value; 754ca6549afSSteven Whitehouse char c; 755ca6549afSSteven Whitehouse *num <<= 4; 756ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 757ca6549afSSteven Whitehouse return -EFAULT; 75882fd5b5dSAndy Shevchenko value = hex_to_bin(c); 75982fd5b5dSAndy Shevchenko if (value >= 0) 76082fd5b5dSAndy Shevchenko *num |= value; 761ca6549afSSteven Whitehouse else 762ca6549afSSteven Whitehouse break; 763ca6549afSSteven Whitehouse } 764ca6549afSSteven Whitehouse return i; 765ca6549afSSteven Whitehouse } 766ca6549afSSteven Whitehouse 767222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 768222f1806SLuiz Capitulino unsigned int maxlen) 7691da177e4SLinus Torvalds { 7701da177e4SLinus Torvalds int i; 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7731da177e4SLinus Torvalds char c; 7741da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7751da177e4SLinus Torvalds return -EFAULT; 7761da177e4SLinus Torvalds switch (c) { 7771da177e4SLinus Torvalds case '\"': 7781da177e4SLinus Torvalds case '\n': 7791da177e4SLinus Torvalds case '\r': 7801da177e4SLinus Torvalds case '\t': 7811da177e4SLinus Torvalds case ' ': 7821da177e4SLinus Torvalds case '=': 7831da177e4SLinus Torvalds break; 7841da177e4SLinus Torvalds default: 7851da177e4SLinus Torvalds goto done; 7863ff50b79SStephen Hemminger } 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds done: 7891da177e4SLinus Torvalds return i; 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds 792bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen, 793bf0813bdSPaul Gortmaker unsigned long *num) 7941da177e4SLinus Torvalds { 795d6182223SPaul Gortmaker int i; 7961da177e4SLinus Torvalds *num = 0; 7971da177e4SLinus Torvalds 798d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 7991da177e4SLinus Torvalds char c; 8001da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8011da177e4SLinus Torvalds return -EFAULT; 8021da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 8031da177e4SLinus Torvalds *num *= 10; 8041da177e4SLinus Torvalds *num += c - '0'; 8051da177e4SLinus Torvalds } else 8061da177e4SLinus Torvalds break; 8071da177e4SLinus Torvalds } 8081da177e4SLinus Torvalds return i; 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 8121da177e4SLinus Torvalds { 813d6182223SPaul Gortmaker int i; 8141da177e4SLinus Torvalds 815d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 8161da177e4SLinus Torvalds char c; 8171da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8181da177e4SLinus Torvalds return -EFAULT; 8191da177e4SLinus Torvalds switch (c) { 8201da177e4SLinus Torvalds case '\"': 8211da177e4SLinus Torvalds case '\n': 8221da177e4SLinus Torvalds case '\r': 8231da177e4SLinus Torvalds case '\t': 8241da177e4SLinus Torvalds case ' ': 8251da177e4SLinus Torvalds goto done_str; 8261da177e4SLinus Torvalds default: 8271da177e4SLinus Torvalds break; 8283ff50b79SStephen Hemminger } 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds done_str: 8311da177e4SLinus Torvalds return i; 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds 83452a62f86SNick Richardson /* Parses imix entries from user buffer. 83552a62f86SNick Richardson * The user buffer should consist of imix entries separated by spaces 83652a62f86SNick Richardson * where each entry consists of size and weight delimited by commas. 83752a62f86SNick Richardson * "size1,weight_1 size2,weight_2 ... size_n,weight_n" for example. 83852a62f86SNick Richardson */ 83952a62f86SNick Richardson static ssize_t get_imix_entries(const char __user *buffer, 84052a62f86SNick Richardson struct pktgen_dev *pkt_dev) 84152a62f86SNick Richardson { 84252a62f86SNick Richardson const int max_digits = 10; 84352a62f86SNick Richardson int i = 0; 84452a62f86SNick Richardson long len; 84552a62f86SNick Richardson char c; 84652a62f86SNick Richardson 84752a62f86SNick Richardson pkt_dev->n_imix_entries = 0; 84852a62f86SNick Richardson 84952a62f86SNick Richardson do { 85052a62f86SNick Richardson unsigned long weight; 85152a62f86SNick Richardson unsigned long size; 85252a62f86SNick Richardson 85352a62f86SNick Richardson len = num_arg(&buffer[i], max_digits, &size); 85452a62f86SNick Richardson if (len < 0) 85552a62f86SNick Richardson return len; 85652a62f86SNick Richardson i += len; 85752a62f86SNick Richardson if (get_user(c, &buffer[i])) 85852a62f86SNick Richardson return -EFAULT; 85952a62f86SNick Richardson /* Check for comma between size_i and weight_i */ 86052a62f86SNick Richardson if (c != ',') 86152a62f86SNick Richardson return -EINVAL; 86252a62f86SNick Richardson i++; 86352a62f86SNick Richardson 86452a62f86SNick Richardson if (size < 14 + 20 + 8) 86552a62f86SNick Richardson size = 14 + 20 + 8; 86652a62f86SNick Richardson 86752a62f86SNick Richardson len = num_arg(&buffer[i], max_digits, &weight); 86852a62f86SNick Richardson if (len < 0) 86952a62f86SNick Richardson return len; 87052a62f86SNick Richardson if (weight <= 0) 87152a62f86SNick Richardson return -EINVAL; 87252a62f86SNick Richardson 87352a62f86SNick Richardson pkt_dev->imix_entries[pkt_dev->n_imix_entries].size = size; 87452a62f86SNick Richardson pkt_dev->imix_entries[pkt_dev->n_imix_entries].weight = weight; 87552a62f86SNick Richardson 87652a62f86SNick Richardson i += len; 87752a62f86SNick Richardson if (get_user(c, &buffer[i])) 87852a62f86SNick Richardson return -EFAULT; 87952a62f86SNick Richardson 88052a62f86SNick Richardson i++; 88152a62f86SNick Richardson pkt_dev->n_imix_entries++; 88252a62f86SNick Richardson 88352a62f86SNick Richardson if (pkt_dev->n_imix_entries > MAX_IMIX_ENTRIES) 88452a62f86SNick Richardson return -E2BIG; 88552a62f86SNick Richardson } while (c == ' '); 88652a62f86SNick Richardson 88752a62f86SNick Richardson return i; 88852a62f86SNick Richardson } 88952a62f86SNick Richardson 890ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 891ca6549afSSteven Whitehouse { 89295c96174SEric Dumazet unsigned int n = 0; 893ca6549afSSteven Whitehouse char c; 894ca6549afSSteven Whitehouse ssize_t i = 0; 895ca6549afSSteven Whitehouse int len; 896ca6549afSSteven Whitehouse 897ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 898ca6549afSSteven Whitehouse do { 899ca6549afSSteven Whitehouse __u32 tmp; 9001ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 901ca6549afSSteven Whitehouse if (len <= 0) 902ca6549afSSteven Whitehouse return len; 903ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 904ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 905ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 906ca6549afSSteven Whitehouse i += len; 907ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 908ca6549afSSteven Whitehouse return -EFAULT; 909ca6549afSSteven Whitehouse i++; 910ca6549afSSteven Whitehouse n++; 911ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 912ca6549afSSteven Whitehouse return -E2BIG; 913ca6549afSSteven Whitehouse } while (c == ','); 914ca6549afSSteven Whitehouse 915ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 916ca6549afSSteven Whitehouse return i; 917ca6549afSSteven Whitehouse } 918ca6549afSSteven Whitehouse 91952e12d5dSDmitry Safonov static __u32 pktgen_read_flag(const char *f, bool *disable) 92052e12d5dSDmitry Safonov { 92152e12d5dSDmitry Safonov __u32 i; 92252e12d5dSDmitry Safonov 92352e12d5dSDmitry Safonov if (f[0] == '!') { 92452e12d5dSDmitry Safonov *disable = true; 92552e12d5dSDmitry Safonov f++; 92652e12d5dSDmitry Safonov } 92752e12d5dSDmitry Safonov 92852e12d5dSDmitry Safonov for (i = 0; i < NR_PKT_FLAGS; i++) { 92952e12d5dSDmitry Safonov if (!IS_ENABLED(CONFIG_XFRM) && i == IPSEC_SHIFT) 93052e12d5dSDmitry Safonov continue; 93152e12d5dSDmitry Safonov 93252e12d5dSDmitry Safonov /* allow only disabling ipv6 flag */ 93352e12d5dSDmitry Safonov if (!*disable && i == IPV6_SHIFT) 93452e12d5dSDmitry Safonov continue; 93552e12d5dSDmitry Safonov 93652e12d5dSDmitry Safonov if (strcmp(f, pkt_flag_names[i]) == 0) 93752e12d5dSDmitry Safonov return 1 << i; 93852e12d5dSDmitry Safonov } 93952e12d5dSDmitry Safonov 94052e12d5dSDmitry Safonov if (strcmp(f, "FLOW_RND") == 0) { 94152e12d5dSDmitry Safonov *disable = !*disable; 94252e12d5dSDmitry Safonov return F_FLOW_SEQ; 94352e12d5dSDmitry Safonov } 94452e12d5dSDmitry Safonov 94552e12d5dSDmitry Safonov return 0; 94652e12d5dSDmitry Safonov } 94752e12d5dSDmitry Safonov 948222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 949222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 950222f1806SLuiz Capitulino loff_t * offset) 9511da177e4SLinus Torvalds { 9528a994a71SJoe Perches struct seq_file *seq = file->private_data; 953d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 954d6182223SPaul Gortmaker int i, max, len; 9551da177e4SLinus Torvalds char name[16], valstr[32]; 9561da177e4SLinus Torvalds unsigned long value = 0; 9571da177e4SLinus Torvalds char *pg_result = NULL; 9581da177e4SLinus Torvalds int tmp = 0; 9591da177e4SLinus Torvalds char buf[128]; 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds if (count < 1) { 964294a0b7fSJoe Perches pr_warn("wrong command format\n"); 9651da177e4SLinus Torvalds return -EINVAL; 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds 968d6182223SPaul Gortmaker max = count; 969d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 9701da177e4SLinus Torvalds if (tmp < 0) { 971294a0b7fSJoe Perches pr_warn("illegal format\n"); 9721da177e4SLinus Torvalds return tmp; 9731da177e4SLinus Torvalds } 974d6182223SPaul Gortmaker i = tmp; 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds /* Read variable name */ 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 97963adc6fbSStephen Hemminger if (len < 0) 980222f1806SLuiz Capitulino return len; 98163adc6fbSStephen Hemminger 9821da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 9831da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 9841da177e4SLinus Torvalds return -EFAULT; 9851da177e4SLinus Torvalds i += len; 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds max = count - i; 9881da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 9891da177e4SLinus Torvalds if (len < 0) 9901da177e4SLinus Torvalds return len; 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds i += len; 9931da177e4SLinus Torvalds 9941da177e4SLinus Torvalds if (debug) { 995a870a02cSArnd Bergmann size_t copy = min_t(size_t, count + 1, 1024); 996a870a02cSArnd Bergmann char *tp = strndup_user(user_buffer, copy); 997a870a02cSArnd Bergmann 998a870a02cSArnd Bergmann if (IS_ERR(tp)) 999a870a02cSArnd Bergmann return PTR_ERR(tp); 1000a870a02cSArnd Bergmann 1001a870a02cSArnd Bergmann pr_debug("%s,%zu buffer -:%s:-\n", name, count, tp); 100229d1df72SGustavo A. R. Silva kfree(tp); 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 10061da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 100763adc6fbSStephen Hemminger if (len < 0) 1008222f1806SLuiz Capitulino return len; 100963adc6fbSStephen Hemminger 10101da177e4SLinus Torvalds i += len; 10111da177e4SLinus Torvalds if (value < 14 + 20 + 8) 10121da177e4SLinus Torvalds value = 14 + 20 + 8; 10131da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 10141da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 10151da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 10161da177e4SLinus Torvalds } 101732be425bSYe Bin sprintf(pg_result, "OK: min_pkt_size=%d", 1018222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 10191da177e4SLinus Torvalds return count; 10201da177e4SLinus Torvalds } 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 10231da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 102463adc6fbSStephen Hemminger if (len < 0) 1025222f1806SLuiz Capitulino return len; 102663adc6fbSStephen Hemminger 10271da177e4SLinus Torvalds i += len; 10281da177e4SLinus Torvalds if (value < 14 + 20 + 8) 10291da177e4SLinus Torvalds value = 14 + 20 + 8; 10301da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 10311da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 10321da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 10331da177e4SLinus Torvalds } 103432be425bSYe Bin sprintf(pg_result, "OK: max_pkt_size=%d", 1035222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 10361da177e4SLinus Torvalds return count; 10371da177e4SLinus Torvalds } 10381da177e4SLinus Torvalds 10391da177e4SLinus Torvalds /* Shortcut for min = max */ 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 10421da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 104363adc6fbSStephen Hemminger if (len < 0) 1044222f1806SLuiz Capitulino return len; 104563adc6fbSStephen Hemminger 10461da177e4SLinus Torvalds i += len; 10471da177e4SLinus Torvalds if (value < 14 + 20 + 8) 10481da177e4SLinus Torvalds value = 14 + 20 + 8; 10491da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 10501da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 10511da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 10521da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 10531da177e4SLinus Torvalds } 105432be425bSYe Bin sprintf(pg_result, "OK: pkt_size=%d", pkt_dev->min_pkt_size); 10551da177e4SLinus Torvalds return count; 10561da177e4SLinus Torvalds } 10571da177e4SLinus Torvalds 105852a62f86SNick Richardson if (!strcmp(name, "imix_weights")) { 105952a62f86SNick Richardson if (pkt_dev->clone_skb > 0) 106052a62f86SNick Richardson return -EINVAL; 106152a62f86SNick Richardson 106252a62f86SNick Richardson len = get_imix_entries(&user_buffer[i], pkt_dev); 106352a62f86SNick Richardson if (len < 0) 106452a62f86SNick Richardson return len; 106552a62f86SNick Richardson 106690149031SNick Richardson fill_imix_distribution(pkt_dev); 106790149031SNick Richardson 106852a62f86SNick Richardson i += len; 106952a62f86SNick Richardson return count; 107052a62f86SNick Richardson } 107152a62f86SNick Richardson 10721da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 10731da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107463adc6fbSStephen Hemminger if (len < 0) 1075222f1806SLuiz Capitulino return len; 107663adc6fbSStephen Hemminger 10771da177e4SLinus Torvalds i += len; 10781da177e4SLinus Torvalds debug = value; 10791da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 10801da177e4SLinus Torvalds return count; 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 10841da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 108563adc6fbSStephen Hemminger if (len < 0) 1086222f1806SLuiz Capitulino return len; 108763adc6fbSStephen Hemminger 10881da177e4SLinus Torvalds i += len; 10891da177e4SLinus Torvalds pkt_dev->nfrags = value; 109032be425bSYe Bin sprintf(pg_result, "OK: frags=%d", pkt_dev->nfrags); 10911da177e4SLinus Torvalds return count; 10921da177e4SLinus Torvalds } 10931da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 10941da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109563adc6fbSStephen Hemminger if (len < 0) 1096222f1806SLuiz Capitulino return len; 109763adc6fbSStephen Hemminger 10981da177e4SLinus Torvalds i += len; 1099fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 1100fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 1101fd29cf72SStephen Hemminger else 11029240d715SEric Dumazet pkt_dev->delay = (u64)value; 1103fd29cf72SStephen Hemminger 1104fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 1105fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 11061da177e4SLinus Torvalds return count; 11071da177e4SLinus Torvalds } 110843d28b65SDaniel Turull if (!strcmp(name, "rate")) { 110943d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 111043d28b65SDaniel Turull if (len < 0) 111143d28b65SDaniel Turull return len; 111243d28b65SDaniel Turull 111343d28b65SDaniel Turull i += len; 111443d28b65SDaniel Turull if (!value) 111543d28b65SDaniel Turull return len; 111643d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 111743d28b65SDaniel Turull if (debug) 1118f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 111943d28b65SDaniel Turull 112043d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 112143d28b65SDaniel Turull return count; 112243d28b65SDaniel Turull } 112343d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 112443d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 112543d28b65SDaniel Turull if (len < 0) 112643d28b65SDaniel Turull return len; 112743d28b65SDaniel Turull 112843d28b65SDaniel Turull i += len; 112943d28b65SDaniel Turull if (!value) 113043d28b65SDaniel Turull return len; 113143d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 113243d28b65SDaniel Turull if (debug) 1133f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 113443d28b65SDaniel Turull 113543d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 113643d28b65SDaniel Turull return count; 113743d28b65SDaniel Turull } 11381da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 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 (value != pkt_dev->udp_src_min) { 11451da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 11461da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 11491da177e4SLinus Torvalds return count; 11501da177e4SLinus Torvalds } 11511da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 11521da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 115363adc6fbSStephen Hemminger if (len < 0) 1154222f1806SLuiz Capitulino return len; 115563adc6fbSStephen Hemminger 11561da177e4SLinus Torvalds i += len; 11571da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 11581da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 11591da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 11621da177e4SLinus Torvalds return count; 11631da177e4SLinus Torvalds } 11641da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 11651da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 116663adc6fbSStephen Hemminger if (len < 0) 1167222f1806SLuiz Capitulino return len; 116863adc6fbSStephen Hemminger 11691da177e4SLinus Torvalds i += len; 11701da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 11711da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 11721da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 11751da177e4SLinus Torvalds return count; 11761da177e4SLinus Torvalds } 11771da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 11781da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 117963adc6fbSStephen Hemminger if (len < 0) 1180222f1806SLuiz Capitulino return len; 118163adc6fbSStephen Hemminger 11821da177e4SLinus Torvalds i += len; 11831da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 11841da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 11851da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 11881da177e4SLinus Torvalds return count; 11891da177e4SLinus Torvalds } 11901da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 11911da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 119263adc6fbSStephen Hemminger if (len < 0) 1193222f1806SLuiz Capitulino return len; 119452a62f86SNick Richardson /* clone_skb is not supported for netif_receive xmit_mode and 119552a62f86SNick Richardson * IMIX mode. 119652a62f86SNick Richardson */ 1197d8873315SNeil Horman if ((value > 0) && 119862f64aedSAlexei Starovoitov ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) || 119962f64aedSAlexei Starovoitov !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) 1200d8873315SNeil Horman return -ENOTSUPP; 120152a62f86SNick Richardson if (value > 0 && pkt_dev->n_imix_entries > 0) 120252a62f86SNick Richardson return -EINVAL; 120352a62f86SNick Richardson 12041da177e4SLinus Torvalds i += len; 12051da177e4SLinus Torvalds pkt_dev->clone_skb = value; 12061da177e4SLinus Torvalds 12071da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 12081da177e4SLinus Torvalds return count; 12091da177e4SLinus Torvalds } 12101da177e4SLinus Torvalds if (!strcmp(name, "count")) { 12111da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 121263adc6fbSStephen Hemminger if (len < 0) 1213222f1806SLuiz Capitulino return len; 121463adc6fbSStephen Hemminger 12151da177e4SLinus Torvalds i += len; 12161da177e4SLinus Torvalds pkt_dev->count = value; 12171da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 12181da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 12191da177e4SLinus Torvalds return count; 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 12221da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 122363adc6fbSStephen Hemminger if (len < 0) 1224222f1806SLuiz Capitulino return len; 122563adc6fbSStephen Hemminger 12261da177e4SLinus Torvalds i += len; 12271da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 12281da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 12291da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 12301da177e4SLinus Torvalds } 1231222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1232222f1806SLuiz Capitulino pkt_dev->src_mac_count); 12331da177e4SLinus Torvalds return count; 12341da177e4SLinus Torvalds } 12351da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 12361da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 123763adc6fbSStephen Hemminger if (len < 0) 1238222f1806SLuiz Capitulino return len; 123963adc6fbSStephen Hemminger 12401da177e4SLinus Torvalds i += len; 12411da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 12421da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 12431da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 12441da177e4SLinus Torvalds } 1245222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1246222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 12471da177e4SLinus Torvalds return count; 12481da177e4SLinus Torvalds } 124938b2cf29SAlexei Starovoitov if (!strcmp(name, "burst")) { 125038b2cf29SAlexei Starovoitov len = num_arg(&user_buffer[i], 10, &value); 125138b2cf29SAlexei Starovoitov if (len < 0) 125238b2cf29SAlexei Starovoitov return len; 125338b2cf29SAlexei Starovoitov 125438b2cf29SAlexei Starovoitov i += len; 12550967f244SJohn Fastabend if ((value > 1) && 12560967f244SJohn Fastabend ((pkt_dev->xmit_mode == M_QUEUE_XMIT) || 12570967f244SJohn Fastabend ((pkt_dev->xmit_mode == M_START_XMIT) && 12580967f244SJohn Fastabend (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))))) 125952d6c8c6SEric Dumazet return -ENOTSUPP; 126038b2cf29SAlexei Starovoitov pkt_dev->burst = value < 1 ? 1 : value; 126132be425bSYe Bin sprintf(pg_result, "OK: burst=%u", pkt_dev->burst); 126238b2cf29SAlexei Starovoitov return count; 126338b2cf29SAlexei Starovoitov } 1264e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1265e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1266e99b99b4SRobert Olsson if (len < 0) 1267e99b99b4SRobert Olsson return len; 1268e99b99b4SRobert Olsson 1269e99b99b4SRobert Olsson i += len; 1270e99b99b4SRobert Olsson 1271e99b99b4SRobert Olsson if (node_possible(value)) { 1272e99b99b4SRobert Olsson pkt_dev->node = value; 1273e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 127426ad7879SEric Dumazet if (pkt_dev->page) { 127526ad7879SEric Dumazet put_page(pkt_dev->page); 127626ad7879SEric Dumazet pkt_dev->page = NULL; 127726ad7879SEric Dumazet } 1278e99b99b4SRobert Olsson } 1279e99b99b4SRobert Olsson else 1280e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1281e99b99b4SRobert Olsson return count; 1282e99b99b4SRobert Olsson } 128362f64aedSAlexei Starovoitov if (!strcmp(name, "xmit_mode")) { 128462f64aedSAlexei Starovoitov char f[32]; 128562f64aedSAlexei Starovoitov 128662f64aedSAlexei Starovoitov memset(f, 0, 32); 128762f64aedSAlexei Starovoitov len = strn_len(&user_buffer[i], sizeof(f) - 1); 128862f64aedSAlexei Starovoitov if (len < 0) 128962f64aedSAlexei Starovoitov return len; 129062f64aedSAlexei Starovoitov 129162f64aedSAlexei Starovoitov if (copy_from_user(f, &user_buffer[i], len)) 129262f64aedSAlexei Starovoitov return -EFAULT; 129362f64aedSAlexei Starovoitov i += len; 129462f64aedSAlexei Starovoitov 129562f64aedSAlexei Starovoitov if (strcmp(f, "start_xmit") == 0) { 129662f64aedSAlexei Starovoitov pkt_dev->xmit_mode = M_START_XMIT; 129762f64aedSAlexei Starovoitov } else if (strcmp(f, "netif_receive") == 0) { 129862f64aedSAlexei Starovoitov /* clone_skb set earlier, not supported in this mode */ 129962f64aedSAlexei Starovoitov if (pkt_dev->clone_skb > 0) 130062f64aedSAlexei Starovoitov return -ENOTSUPP; 130162f64aedSAlexei Starovoitov 130262f64aedSAlexei Starovoitov pkt_dev->xmit_mode = M_NETIF_RECEIVE; 13039eea9222SAlexei Starovoitov 13049eea9222SAlexei Starovoitov /* make sure new packet is allocated every time 13059eea9222SAlexei Starovoitov * pktgen_xmit() is called 13069eea9222SAlexei Starovoitov */ 13079eea9222SAlexei Starovoitov pkt_dev->last_ok = 1; 13080967f244SJohn Fastabend } else if (strcmp(f, "queue_xmit") == 0) { 13090967f244SJohn Fastabend pkt_dev->xmit_mode = M_QUEUE_XMIT; 13100967f244SJohn Fastabend pkt_dev->last_ok = 1; 131162f64aedSAlexei Starovoitov } else { 131262f64aedSAlexei Starovoitov sprintf(pg_result, 131362f64aedSAlexei Starovoitov "xmit_mode -:%s:- unknown\nAvailable modes: %s", 131462f64aedSAlexei Starovoitov f, "start_xmit, netif_receive\n"); 131562f64aedSAlexei Starovoitov return count; 131662f64aedSAlexei Starovoitov } 131762f64aedSAlexei Starovoitov sprintf(pg_result, "OK: xmit_mode=%s", f); 131862f64aedSAlexei Starovoitov return count; 131962f64aedSAlexei Starovoitov } 13201da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 132152e12d5dSDmitry Safonov __u32 flag; 13221da177e4SLinus Torvalds char f[32]; 132352e12d5dSDmitry Safonov bool disable = false; 132452e12d5dSDmitry Safonov 13251da177e4SLinus Torvalds memset(f, 0, 32); 13261da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 132763adc6fbSStephen Hemminger if (len < 0) 1328222f1806SLuiz Capitulino return len; 132963adc6fbSStephen Hemminger 13301da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 13311da177e4SLinus Torvalds return -EFAULT; 13321da177e4SLinus Torvalds i += len; 13331da177e4SLinus Torvalds 133452e12d5dSDmitry Safonov flag = pktgen_read_flag(f, &disable); 13351da177e4SLinus Torvalds 133652e12d5dSDmitry Safonov if (flag) { 133752e12d5dSDmitry Safonov if (disable) 133852e12d5dSDmitry Safonov pkt_dev->flags &= ~flag; 133952e12d5dSDmitry Safonov else 134052e12d5dSDmitry Safonov pkt_dev->flags |= flag; 134152e12d5dSDmitry Safonov } else { 1342222f1806SLuiz Capitulino sprintf(pg_result, 1343222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 13441da177e4SLinus Torvalds f, 13451ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 134672f8e06fSMathias Krause "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, " 134772f8e06fSMathias Krause "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, " 134872f8e06fSMathias Krause "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, " 1349afb84b62SJesper Dangaard Brouer "NO_TIMESTAMP, " 135072f8e06fSMathias Krause #ifdef CONFIG_XFRM 135172f8e06fSMathias Krause "IPSEC, " 135272f8e06fSMathias Krause #endif 135372f8e06fSMathias Krause "NODE_ALLOC\n"); 13541da177e4SLinus Torvalds return count; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 13571da177e4SLinus Torvalds return count; 13581da177e4SLinus Torvalds } 13591da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 13601da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 136163adc6fbSStephen Hemminger if (len < 0) 1362222f1806SLuiz Capitulino return len; 13631da177e4SLinus Torvalds 13641da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13651da177e4SLinus Torvalds return -EFAULT; 13661da177e4SLinus Torvalds buf[len] = 0; 13671da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 13681da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 1369f15f084fSJakub Kicinski strcpy(pkt_dev->dst_min, buf); 13701da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 13711da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds if (debug) 1374f342cda7SJoe Perches pr_debug("dst_min set to: %s\n", pkt_dev->dst_min); 13751da177e4SLinus Torvalds i += len; 13761da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 13771da177e4SLinus Torvalds return count; 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 13801da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 138163adc6fbSStephen Hemminger if (len < 0) 1382222f1806SLuiz Capitulino return len; 138363adc6fbSStephen Hemminger 13841da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13851da177e4SLinus Torvalds return -EFAULT; 13861da177e4SLinus Torvalds buf[len] = 0; 13871da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 13881da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 1389f15f084fSJakub Kicinski strcpy(pkt_dev->dst_max, buf); 13901da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 13911da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 13921da177e4SLinus Torvalds } 13931da177e4SLinus Torvalds if (debug) 1394f342cda7SJoe Perches pr_debug("dst_max set to: %s\n", pkt_dev->dst_max); 13951da177e4SLinus Torvalds i += len; 13961da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 13971da177e4SLinus Torvalds return count; 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 14001da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1401222f1806SLuiz Capitulino if (len < 0) 1402222f1806SLuiz Capitulino return len; 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14071da177e4SLinus Torvalds return -EFAULT; 14081da177e4SLinus Torvalds buf[len] = 0; 14091da177e4SLinus Torvalds 1410c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL); 141147a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); 14121da177e4SLinus Torvalds 14134e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr; 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds if (debug) 1416f342cda7SJoe Perches pr_debug("dst6 set to: %s\n", buf); 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds i += len; 14191da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 14201da177e4SLinus Torvalds return count; 14211da177e4SLinus Torvalds } 14221da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 14231da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1424222f1806SLuiz Capitulino if (len < 0) 1425222f1806SLuiz Capitulino return len; 14261da177e4SLinus Torvalds 14271da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14281da177e4SLinus Torvalds 14291da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14301da177e4SLinus Torvalds return -EFAULT; 14311da177e4SLinus Torvalds buf[len] = 0; 14321da177e4SLinus Torvalds 1433c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL); 143447a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); 14351da177e4SLinus Torvalds 14364e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr; 14371da177e4SLinus Torvalds if (debug) 1438f342cda7SJoe Perches pr_debug("dst6_min set to: %s\n", buf); 14391da177e4SLinus Torvalds 14401da177e4SLinus Torvalds i += len; 14411da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 14421da177e4SLinus Torvalds return count; 14431da177e4SLinus Torvalds } 14441da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 14451da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1446222f1806SLuiz Capitulino if (len < 0) 1447222f1806SLuiz Capitulino return len; 14481da177e4SLinus Torvalds 14491da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14501da177e4SLinus Torvalds 14511da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14521da177e4SLinus Torvalds return -EFAULT; 14531da177e4SLinus Torvalds buf[len] = 0; 14541da177e4SLinus Torvalds 1455c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL); 145647a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); 14571da177e4SLinus Torvalds 14581da177e4SLinus Torvalds if (debug) 1459f342cda7SJoe Perches pr_debug("dst6_max set to: %s\n", buf); 14601da177e4SLinus Torvalds 14611da177e4SLinus Torvalds i += len; 14621da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 14631da177e4SLinus Torvalds return count; 14641da177e4SLinus Torvalds } 14651da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 14661da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1467222f1806SLuiz Capitulino if (len < 0) 1468222f1806SLuiz Capitulino return len; 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 14711da177e4SLinus Torvalds 14721da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14731da177e4SLinus Torvalds return -EFAULT; 14741da177e4SLinus Torvalds buf[len] = 0; 14751da177e4SLinus Torvalds 1476c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL); 147747a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); 14781da177e4SLinus Torvalds 14794e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds if (debug) 1482f342cda7SJoe Perches pr_debug("src6 set to: %s\n", buf); 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds i += len; 14851da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 14861da177e4SLinus Torvalds return count; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 14891da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 149063adc6fbSStephen Hemminger if (len < 0) 1491222f1806SLuiz Capitulino return len; 149263adc6fbSStephen Hemminger 14931da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14941da177e4SLinus Torvalds return -EFAULT; 14951da177e4SLinus Torvalds buf[len] = 0; 14961da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 14971da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 1498f15f084fSJakub Kicinski strcpy(pkt_dev->src_min, buf); 14991da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 15001da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 15011da177e4SLinus Torvalds } 15021da177e4SLinus Torvalds if (debug) 1503f342cda7SJoe Perches pr_debug("src_min set to: %s\n", pkt_dev->src_min); 15041da177e4SLinus Torvalds i += len; 15051da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 15061da177e4SLinus Torvalds return count; 15071da177e4SLinus Torvalds } 15081da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 15091da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 151063adc6fbSStephen Hemminger if (len < 0) 1511222f1806SLuiz Capitulino return len; 151263adc6fbSStephen Hemminger 15131da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 15141da177e4SLinus Torvalds return -EFAULT; 15151da177e4SLinus Torvalds buf[len] = 0; 15161da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 15171da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 1518f15f084fSJakub Kicinski strcpy(pkt_dev->src_max, buf); 15191da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 15201da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 15211da177e4SLinus Torvalds } 15221da177e4SLinus Torvalds if (debug) 1523f342cda7SJoe Perches pr_debug("src_max set to: %s\n", pkt_dev->src_max); 15241da177e4SLinus Torvalds i += len; 15251da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 15261da177e4SLinus Torvalds return count; 15271da177e4SLinus Torvalds } 15281da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 15291da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 153063adc6fbSStephen Hemminger if (len < 0) 1531222f1806SLuiz Capitulino return len; 153263adc6fbSStephen Hemminger 15331da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 15341da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 15351da177e4SLinus Torvalds return -EFAULT; 15361da177e4SLinus Torvalds 15374940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->dst_mac)) 15384940fc88SAlexey Dobriyan return -EINVAL; 15391da177e4SLinus Torvalds /* Set up Dest MAC */ 15409ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); 15411da177e4SLinus Torvalds 15424940fc88SAlexey Dobriyan sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); 15431da177e4SLinus Torvalds return count; 15441da177e4SLinus Torvalds } 15451da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 15461da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 154763adc6fbSStephen Hemminger if (len < 0) 1548222f1806SLuiz Capitulino return len; 154963adc6fbSStephen Hemminger 15501da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 15511da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 15521da177e4SLinus Torvalds return -EFAULT; 15531da177e4SLinus Torvalds 15544940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->src_mac)) 15554940fc88SAlexey Dobriyan return -EINVAL; 1556ce5d0b47SAdit Ranadive /* Set up Src MAC */ 15579ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); 1558ce5d0b47SAdit Ranadive 15594940fc88SAlexey Dobriyan sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); 15601da177e4SLinus Torvalds return count; 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds 15631da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 15641da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 15651da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 15661da177e4SLinus Torvalds return count; 15671da177e4SLinus Torvalds } 15681da177e4SLinus Torvalds 15691da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 15701da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 157163adc6fbSStephen Hemminger if (len < 0) 1572222f1806SLuiz Capitulino return len; 157363adc6fbSStephen Hemminger 15741da177e4SLinus Torvalds i += len; 15751da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15761da177e4SLinus Torvalds value = MAX_CFLOWS; 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds pkt_dev->cflows = value; 15791da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15801da177e4SLinus Torvalds return count; 15811da177e4SLinus Torvalds } 15826bae9190SFan Du #ifdef CONFIG_XFRM 1583de4aee7dSFan Du if (!strcmp(name, "spi")) { 1584de4aee7dSFan Du len = num_arg(&user_buffer[i], 10, &value); 1585de4aee7dSFan Du if (len < 0) 1586de4aee7dSFan Du return len; 1587de4aee7dSFan Du 1588de4aee7dSFan Du i += len; 1589de4aee7dSFan Du pkt_dev->spi = value; 1590de4aee7dSFan Du sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); 1591de4aee7dSFan Du return count; 1592de4aee7dSFan Du } 15936bae9190SFan Du #endif 15941da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15951da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 159663adc6fbSStephen Hemminger if (len < 0) 1597222f1806SLuiz Capitulino return len; 159863adc6fbSStephen Hemminger 15991da177e4SLinus Torvalds i += len; 16001da177e4SLinus Torvalds pkt_dev->lflow = value; 16011da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 16021da177e4SLinus Torvalds return count; 16031da177e4SLinus Torvalds } 16041da177e4SLinus Torvalds 160545b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 160645b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 160763adc6fbSStephen Hemminger if (len < 0) 160845b270f8SRobert Olsson return len; 160963adc6fbSStephen Hemminger 161045b270f8SRobert Olsson i += len; 161145b270f8SRobert Olsson pkt_dev->queue_map_min = value; 161245b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 161345b270f8SRobert Olsson return count; 161445b270f8SRobert Olsson } 161545b270f8SRobert Olsson 161645b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 161745b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 161863adc6fbSStephen Hemminger if (len < 0) 161945b270f8SRobert Olsson return len; 162063adc6fbSStephen Hemminger 162145b270f8SRobert Olsson i += len; 162245b270f8SRobert Olsson pkt_dev->queue_map_max = value; 162345b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 162445b270f8SRobert Olsson return count; 162545b270f8SRobert Olsson } 162645b270f8SRobert Olsson 1627ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 162895c96174SEric Dumazet unsigned int n, cnt; 1629cfcabdccSStephen Hemminger 1630ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1631cfcabdccSStephen Hemminger if (len < 0) 1632cfcabdccSStephen Hemminger return len; 1633ca6549afSSteven Whitehouse i += len; 1634cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1635ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1636cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1637ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1638ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 163934954ddcSFrancesco Fondelli 164034954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 164134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 164234954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 164334954ddcSFrancesco Fondelli 164434954ddcSFrancesco Fondelli if (debug) 1645f342cda7SJoe Perches pr_debug("VLAN/SVLAN auto turned off\n"); 164634954ddcSFrancesco Fondelli } 164734954ddcSFrancesco Fondelli return count; 164834954ddcSFrancesco Fondelli } 164934954ddcSFrancesco Fondelli 165034954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 165134954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 165263adc6fbSStephen Hemminger if (len < 0) 165334954ddcSFrancesco Fondelli return len; 165463adc6fbSStephen Hemminger 165534954ddcSFrancesco Fondelli i += len; 165634954ddcSFrancesco Fondelli if (value <= 4095) { 165734954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 165834954ddcSFrancesco Fondelli 165934954ddcSFrancesco Fondelli if (debug) 1660f342cda7SJoe Perches pr_debug("VLAN turned on\n"); 166134954ddcSFrancesco Fondelli 166234954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1663f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 166434954ddcSFrancesco Fondelli 166534954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 166634954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 166734954ddcSFrancesco Fondelli } else { 166834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 166934954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 167034954ddcSFrancesco Fondelli 167134954ddcSFrancesco Fondelli if (debug) 1672f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 167334954ddcSFrancesco Fondelli } 167434954ddcSFrancesco Fondelli return count; 167534954ddcSFrancesco Fondelli } 167634954ddcSFrancesco Fondelli 167734954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 167834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 167963adc6fbSStephen Hemminger if (len < 0) 168034954ddcSFrancesco Fondelli return len; 168163adc6fbSStephen Hemminger 168234954ddcSFrancesco Fondelli i += len; 168334954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 168434954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 168534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 168634954ddcSFrancesco Fondelli } else { 168734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 168834954ddcSFrancesco Fondelli } 168934954ddcSFrancesco Fondelli return count; 169034954ddcSFrancesco Fondelli } 169134954ddcSFrancesco Fondelli 169234954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 169334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 169463adc6fbSStephen Hemminger if (len < 0) 169534954ddcSFrancesco Fondelli return len; 169663adc6fbSStephen Hemminger 169734954ddcSFrancesco Fondelli i += len; 169834954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 169934954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 170034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 170134954ddcSFrancesco Fondelli } else { 170234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 170334954ddcSFrancesco Fondelli } 170434954ddcSFrancesco Fondelli return count; 170534954ddcSFrancesco Fondelli } 170634954ddcSFrancesco Fondelli 170734954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 170834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 170963adc6fbSStephen Hemminger if (len < 0) 171034954ddcSFrancesco Fondelli return len; 171163adc6fbSStephen Hemminger 171234954ddcSFrancesco Fondelli i += len; 171334954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 171434954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 171534954ddcSFrancesco Fondelli 171634954ddcSFrancesco Fondelli if (debug) 1717f342cda7SJoe Perches pr_debug("SVLAN turned on\n"); 171834954ddcSFrancesco Fondelli 171934954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1720f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 172134954ddcSFrancesco Fondelli 172234954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 172334954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 172434954ddcSFrancesco Fondelli } else { 172534954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 172634954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 172734954ddcSFrancesco Fondelli 172834954ddcSFrancesco Fondelli if (debug) 1729f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 173034954ddcSFrancesco Fondelli } 173134954ddcSFrancesco Fondelli return count; 173234954ddcSFrancesco Fondelli } 173334954ddcSFrancesco Fondelli 173434954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 173534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 173663adc6fbSStephen Hemminger if (len < 0) 173734954ddcSFrancesco Fondelli return len; 173863adc6fbSStephen Hemminger 173934954ddcSFrancesco Fondelli i += len; 174034954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 174134954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 174234954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 174334954ddcSFrancesco Fondelli } else { 174434954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 174534954ddcSFrancesco Fondelli } 174634954ddcSFrancesco Fondelli return count; 174734954ddcSFrancesco Fondelli } 174834954ddcSFrancesco Fondelli 174934954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 175034954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 175163adc6fbSStephen Hemminger if (len < 0) 175234954ddcSFrancesco Fondelli return len; 175363adc6fbSStephen Hemminger 175434954ddcSFrancesco Fondelli i += len; 175534954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 175634954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 175734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 175834954ddcSFrancesco Fondelli } else { 175934954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 176034954ddcSFrancesco Fondelli } 1761ca6549afSSteven Whitehouse return count; 1762ca6549afSSteven Whitehouse } 1763ca6549afSSteven Whitehouse 17641ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 17651ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17661ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 176763adc6fbSStephen Hemminger if (len < 0) 17681ca7768cSFrancesco Fondelli return len; 176963adc6fbSStephen Hemminger 17701ca7768cSFrancesco Fondelli i += len; 17711ca7768cSFrancesco Fondelli if (len == 2) { 17721ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 17731ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 17741ca7768cSFrancesco Fondelli } else { 17751ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 17761ca7768cSFrancesco Fondelli } 17771ca7768cSFrancesco Fondelli return count; 17781ca7768cSFrancesco Fondelli } 17791ca7768cSFrancesco Fondelli 17801ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 17811ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17821ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 178363adc6fbSStephen Hemminger if (len < 0) 17841ca7768cSFrancesco Fondelli return len; 178563adc6fbSStephen Hemminger 17861ca7768cSFrancesco Fondelli i += len; 17871ca7768cSFrancesco Fondelli if (len == 2) { 17881ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17891ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17901ca7768cSFrancesco Fondelli } else { 17911ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17921ca7768cSFrancesco Fondelli } 17931ca7768cSFrancesco Fondelli return count; 17941ca7768cSFrancesco Fondelli } 17951ca7768cSFrancesco Fondelli 17969e50e3acSJohn Fastabend if (!strcmp(name, "skb_priority")) { 17979e50e3acSJohn Fastabend len = num_arg(&user_buffer[i], 9, &value); 17989e50e3acSJohn Fastabend if (len < 0) 17999e50e3acSJohn Fastabend return len; 18009e50e3acSJohn Fastabend 18019e50e3acSJohn Fastabend i += len; 18029e50e3acSJohn Fastabend pkt_dev->skb_priority = value; 18039e50e3acSJohn Fastabend sprintf(pg_result, "OK: skb_priority=%i", 18049e50e3acSJohn Fastabend pkt_dev->skb_priority); 18059e50e3acSJohn Fastabend return count; 18069e50e3acSJohn Fastabend } 18079e50e3acSJohn Fastabend 18081da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 18091da177e4SLinus Torvalds return -EINVAL; 18101da177e4SLinus Torvalds } 18111da177e4SLinus Torvalds 1812d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 18131da177e4SLinus Torvalds { 1814*359745d7SMuchun Song return single_open(file, pktgen_if_show, pde_data(inode)); 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds 181797a32539SAlexey Dobriyan static const struct proc_ops pktgen_if_proc_ops = { 181897a32539SAlexey Dobriyan .proc_open = pktgen_if_open, 181997a32539SAlexey Dobriyan .proc_read = seq_read, 182097a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 182197a32539SAlexey Dobriyan .proc_write = pktgen_if_write, 182297a32539SAlexey Dobriyan .proc_release = single_release, 1823d50a6b56SStephen Hemminger }; 1824d50a6b56SStephen Hemminger 1825d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1826d50a6b56SStephen Hemminger { 1827d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1828648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1829d50a6b56SStephen Hemminger 1830d50a6b56SStephen Hemminger BUG_ON(!t); 1831d50a6b56SStephen Hemminger 183297dc48e2SThomas Graf seq_puts(seq, "Running: "); 18331da177e4SLinus Torvalds 18348788370aSJesper Dangaard Brouer rcu_read_lock(); 18358788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 18361da177e4SLinus Torvalds if (pkt_dev->running) 1837593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 18381da177e4SLinus Torvalds 183997dc48e2SThomas Graf seq_puts(seq, "\nStopped: "); 18401da177e4SLinus Torvalds 18418788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 18421da177e4SLinus Torvalds if (!pkt_dev->running) 1843593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 18441da177e4SLinus Torvalds 18451da177e4SLinus Torvalds if (t->result[0]) 1846d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 18471da177e4SLinus Torvalds else 184897dc48e2SThomas Graf seq_puts(seq, "\nResult: NA\n"); 18491da177e4SLinus Torvalds 18508788370aSJesper Dangaard Brouer rcu_read_unlock(); 18511da177e4SLinus Torvalds 1852d50a6b56SStephen Hemminger return 0; 18531da177e4SLinus Torvalds } 18541da177e4SLinus Torvalds 1855d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1856d50a6b56SStephen Hemminger const char __user * user_buffer, 1857d50a6b56SStephen Hemminger size_t count, loff_t * offset) 18581da177e4SLinus Torvalds { 18598a994a71SJoe Perches struct seq_file *seq = file->private_data; 1860d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1861d6182223SPaul Gortmaker int i, max, len, ret; 18621da177e4SLinus Torvalds char name[40]; 18631da177e4SLinus Torvalds char *pg_result; 18641da177e4SLinus Torvalds 18651da177e4SLinus Torvalds if (count < 1) { 18661da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 18671da177e4SLinus Torvalds return -EINVAL; 18681da177e4SLinus Torvalds } 18691da177e4SLinus Torvalds 1870d6182223SPaul Gortmaker max = count; 1871d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 18721da177e4SLinus Torvalds if (len < 0) 18731da177e4SLinus Torvalds return len; 18741da177e4SLinus Torvalds 1875d6182223SPaul Gortmaker i = len; 18761da177e4SLinus Torvalds 18771da177e4SLinus Torvalds /* Read variable name */ 18781da177e4SLinus Torvalds 18791da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 18801da177e4SLinus Torvalds if (len < 0) 18811da177e4SLinus Torvalds return len; 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 18841da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 18851da177e4SLinus Torvalds return -EFAULT; 18861da177e4SLinus Torvalds i += len; 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds max = count - i; 18891da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 18901da177e4SLinus Torvalds if (len < 0) 18911da177e4SLinus Torvalds return len; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds i += len; 18941da177e4SLinus Torvalds 18951da177e4SLinus Torvalds if (debug) 1896f342cda7SJoe Perches pr_debug("t=%s, count=%lu\n", name, (unsigned long)count); 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds if (!t) { 1899f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 19001da177e4SLinus Torvalds ret = -EINVAL; 19011da177e4SLinus Torvalds goto out; 19021da177e4SLinus Torvalds } 19031da177e4SLinus Torvalds 19041da177e4SLinus Torvalds pg_result = &(t->result[0]); 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 19071da177e4SLinus Torvalds char f[32]; 19081da177e4SLinus Torvalds memset(f, 0, 32); 19091da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 19101da177e4SLinus Torvalds if (len < 0) { 19111da177e4SLinus Torvalds ret = len; 19121da177e4SLinus Torvalds goto out; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 19151da177e4SLinus Torvalds return -EFAULT; 19161da177e4SLinus Torvalds i += len; 19176146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1918604dfd6eSCong Wang ret = pktgen_add_device(t, f); 19196146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1920604dfd6eSCong Wang if (!ret) { 19211da177e4SLinus Torvalds ret = count; 19221da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 1923604dfd6eSCong Wang } else 1924604dfd6eSCong Wang sprintf(pg_result, "ERROR: can not add device %s", f); 19251da177e4SLinus Torvalds goto out; 19261da177e4SLinus Torvalds } 19271da177e4SLinus Torvalds 19281da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 19296146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 193095ed63f7SArthur Kepner t->control |= T_REMDEVALL; 19316146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1932121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 19331da177e4SLinus Torvalds ret = count; 19341da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 19351da177e4SLinus Torvalds goto out; 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 19381da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1939b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 19401da177e4SLinus Torvalds ret = count; 19411da177e4SLinus Torvalds goto out; 19421da177e4SLinus Torvalds } 19431da177e4SLinus Torvalds 19441da177e4SLinus Torvalds ret = -EINVAL; 19451da177e4SLinus Torvalds out: 19461da177e4SLinus Torvalds return ret; 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 1949d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 19501da177e4SLinus Torvalds { 1951*359745d7SMuchun Song return single_open(file, pktgen_thread_show, pde_data(inode)); 19521da177e4SLinus Torvalds } 19531da177e4SLinus Torvalds 195497a32539SAlexey Dobriyan static const struct proc_ops pktgen_thread_proc_ops = { 195597a32539SAlexey Dobriyan .proc_open = pktgen_thread_open, 195697a32539SAlexey Dobriyan .proc_read = seq_read, 195797a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 195897a32539SAlexey Dobriyan .proc_write = pktgen_thread_write, 195997a32539SAlexey Dobriyan .proc_release = single_release, 1960d50a6b56SStephen Hemminger }; 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds /* Think find or remove for NN */ 19634e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, 19644e58a027SCong Wang const char *ifname, int remove) 19651da177e4SLinus Torvalds { 19661da177e4SLinus Torvalds struct pktgen_thread *t; 19671da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 19683e984840SEric Dumazet bool exact = (remove == FIND); 19691da177e4SLinus Torvalds 19704e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 19713e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 19721da177e4SLinus Torvalds if (pkt_dev) { 19731da177e4SLinus Torvalds if (remove) { 197495ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 197595ed63f7SArthur Kepner t->control |= T_REMDEV; 19761da177e4SLinus Torvalds } 19771da177e4SLinus Torvalds break; 19781da177e4SLinus Torvalds } 19791da177e4SLinus Torvalds } 19801da177e4SLinus Torvalds return pkt_dev; 19811da177e4SLinus Torvalds } 19821da177e4SLinus Torvalds 198395ed63f7SArthur Kepner /* 198495ed63f7SArthur Kepner * mark a device for removal 198595ed63f7SArthur Kepner */ 19864e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname) 19871da177e4SLinus Torvalds { 19881da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 198995ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 199095ed63f7SArthur Kepner int i = 0; 199195ed63f7SArthur Kepner 19926146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1993f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 199495ed63f7SArthur Kepner 199595ed63f7SArthur Kepner while (1) { 199695ed63f7SArthur Kepner 19974e58a027SCong Wang pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE); 1998222f1806SLuiz Capitulino if (pkt_dev == NULL) 1999222f1806SLuiz Capitulino break; /* success */ 200095ed63f7SArthur Kepner 20016146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 2002f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 2003f9467eaeSJoe Perches __func__, ifname); 200495ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 20056146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 200695ed63f7SArthur Kepner 200795ed63f7SArthur Kepner if (++i >= max_tries) { 2008f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 2009f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 201095ed63f7SArthur Kepner break; 201195ed63f7SArthur Kepner } 201295ed63f7SArthur Kepner 201395ed63f7SArthur Kepner } 201495ed63f7SArthur Kepner 20156146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 201639df232fSStephen Hemminger } 201795ed63f7SArthur Kepner 20184e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) 201939df232fSStephen Hemminger { 202039df232fSStephen Hemminger struct pktgen_thread *t; 202139df232fSStephen Hemminger 20229a0b1e8bSEric Dumazet mutex_lock(&pktgen_thread_lock); 20239a0b1e8bSEric Dumazet 20244e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 202539df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 202639df232fSStephen Hemminger 20279a0b1e8bSEric Dumazet if_lock(t); 20289a0b1e8bSEric Dumazet list_for_each_entry(pkt_dev, &t->if_list, list) { 202939df232fSStephen Hemminger if (pkt_dev->odev != dev) 203039df232fSStephen Hemminger continue; 203139df232fSStephen Hemminger 2032a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 203339df232fSStephen Hemminger 20342975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 20354e58a027SCong Wang pn->proc_dir, 203697a32539SAlexey Dobriyan &pktgen_if_proc_ops, 20372975315bSAlexey Dobriyan pkt_dev); 203839df232fSStephen Hemminger if (!pkt_dev->entry) 2039f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 2040f9467eaeSJoe Perches dev->name); 204139df232fSStephen Hemminger break; 204239df232fSStephen Hemminger } 20439a0b1e8bSEric Dumazet if_unlock(t); 204439df232fSStephen Hemminger } 20459a0b1e8bSEric Dumazet mutex_unlock(&pktgen_thread_lock); 20461da177e4SLinus Torvalds } 20471da177e4SLinus Torvalds 2048222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 2049222f1806SLuiz Capitulino unsigned long event, void *ptr) 20501da177e4SLinus Torvalds { 2051351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 20524e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id); 20531da177e4SLinus Torvalds 20544e58a027SCong Wang if (pn->pktgen_exiting) 2055e9dc8653SEric W. Biederman return NOTIFY_DONE; 2056e9dc8653SEric W. Biederman 20571da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 20581da177e4SLinus Torvalds * as we run under the RTNL lock. 20591da177e4SLinus Torvalds */ 20601da177e4SLinus Torvalds 20611da177e4SLinus Torvalds switch (event) { 206239df232fSStephen Hemminger case NETDEV_CHANGENAME: 20634e58a027SCong Wang pktgen_change_name(pn, dev); 20641da177e4SLinus Torvalds break; 20651da177e4SLinus Torvalds 20661da177e4SLinus Torvalds case NETDEV_UNREGISTER: 20674e58a027SCong Wang pktgen_mark_device(pn, dev->name); 20681da177e4SLinus Torvalds break; 20693ff50b79SStephen Hemminger } 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds return NOTIFY_DONE; 20721da177e4SLinus Torvalds } 20731da177e4SLinus Torvalds 20744e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn, 20754e58a027SCong Wang struct pktgen_dev *pkt_dev, 207663adc6fbSStephen Hemminger const char *ifname) 2077e6fce5b9SRobert Olsson { 2078e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 2079d6182223SPaul Gortmaker int i; 2080e6fce5b9SRobert Olsson 2081e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 2082e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 2083e6fce5b9SRobert Olsson break; 2084e6fce5b9SRobert Olsson 2085e6fce5b9SRobert Olsson b[i] = ifname[i]; 2086e6fce5b9SRobert Olsson } 2087e6fce5b9SRobert Olsson b[i] = 0; 2088e6fce5b9SRobert Olsson 20894e58a027SCong Wang return dev_get_by_name(pn->net, b); 2090e6fce5b9SRobert Olsson } 2091e6fce5b9SRobert Olsson 2092e6fce5b9SRobert Olsson 20931da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 20941da177e4SLinus Torvalds 20954e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn, 20964e58a027SCong Wang struct pktgen_dev *pkt_dev, const char *ifname) 2097222f1806SLuiz Capitulino { 20981da177e4SLinus Torvalds struct net_device *odev; 209939df232fSStephen Hemminger int err; 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds /* Clean old setups */ 21021da177e4SLinus Torvalds if (pkt_dev->odev) { 2103035f1f2bSEric Dumazet dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); 21041da177e4SLinus Torvalds pkt_dev->odev = NULL; 21051da177e4SLinus Torvalds } 21061da177e4SLinus Torvalds 21074e58a027SCong Wang odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname); 21081da177e4SLinus Torvalds if (!odev) { 2109f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 211039df232fSStephen Hemminger return -ENODEV; 21111da177e4SLinus Torvalds } 211239df232fSStephen Hemminger 21131e09e581SLukas Wunner if (odev->type != ARPHRD_ETHER && odev->type != ARPHRD_LOOPBACK) { 21141e09e581SLukas Wunner pr_err("not an ethernet or loopback device: \"%s\"\n", ifname); 211539df232fSStephen Hemminger err = -EINVAL; 211639df232fSStephen Hemminger } else if (!netif_running(odev)) { 2117f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 211839df232fSStephen Hemminger err = -ENETDOWN; 211939df232fSStephen Hemminger } else { 21201da177e4SLinus Torvalds pkt_dev->odev = odev; 2121035f1f2bSEric Dumazet netdev_tracker_alloc(odev, &pkt_dev->dev_tracker, GFP_KERNEL); 212239df232fSStephen Hemminger return 0; 212339df232fSStephen Hemminger } 21241da177e4SLinus Torvalds 21251da177e4SLinus Torvalds dev_put(odev); 212639df232fSStephen Hemminger return err; 21271da177e4SLinus Torvalds } 21281da177e4SLinus Torvalds 21291da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 21301da177e4SLinus Torvalds * structure to have the right information to create/send packets 21311da177e4SLinus Torvalds */ 21321da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 21331da177e4SLinus Torvalds { 213464c00d81SAndrew Gallatin int ntxq; 213564c00d81SAndrew Gallatin 21361da177e4SLinus Torvalds if (!pkt_dev->odev) { 2137f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2138222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2139222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 21401da177e4SLinus Torvalds return; 21411da177e4SLinus Torvalds } 21421da177e4SLinus Torvalds 214364c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 214464c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2145bfdbc0acSRobert Olsson 214664c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2147294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 214888271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2149593f63b0SEric Dumazet pkt_dev->odevname); 215026e29eedSDan Carpenter pkt_dev->queue_map_min = (ntxq ?: 1) - 1; 215164c00d81SAndrew Gallatin } 215288271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2153294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 215488271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2155593f63b0SEric Dumazet pkt_dev->odevname); 215626e29eedSDan Carpenter pkt_dev->queue_map_max = (ntxq ?: 1) - 1; 215764c00d81SAndrew Gallatin } 215864c00d81SAndrew Gallatin 21591da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 21601da177e4SLinus Torvalds 2161f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 21629ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds /* Set up Dest MAC */ 21659ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); 21661da177e4SLinus Torvalds 21671da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 21684c139b8cSAmerigo Wang int i, set = 0, err = 1; 21694c139b8cSAmerigo Wang struct inet6_dev *idev; 21704c139b8cSAmerigo Wang 217168bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 217268bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr) 217368bf9f0bSAmerigo Wang + sizeof(struct udphdr) 217468bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 217568bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 217668bf9f0bSAmerigo Wang } 217768bf9f0bSAmerigo Wang 2178df7e8e2eSEric Dumazet for (i = 0; i < sizeof(struct in6_addr); i++) 21791da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 21801da177e4SLinus Torvalds set = 1; 21811da177e4SLinus Torvalds break; 21821da177e4SLinus Torvalds } 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds if (!set) { 21851da177e4SLinus Torvalds 21861da177e4SLinus Torvalds /* 21871da177e4SLinus Torvalds * Use linklevel address if unconfigured. 21881da177e4SLinus Torvalds * 21891da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 21901da177e4SLinus Torvalds */ 21911da177e4SLinus Torvalds 21928814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 219363adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 219463adc6fbSStephen Hemminger if (idev) { 21951da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 21961da177e4SLinus Torvalds 21971da177e4SLinus Torvalds read_lock_bh(&idev->lock); 21984c139b8cSAmerigo Wang list_for_each_entry(ifp, &idev->addr_list, if_list) { 21994c139b8cSAmerigo Wang if ((ifp->scope & IFA_LINK) && 2200f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 22014e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = ifp->addr; 22021da177e4SLinus Torvalds err = 0; 22031da177e4SLinus Torvalds break; 22041da177e4SLinus Torvalds } 22051da177e4SLinus Torvalds } 22061da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 22071da177e4SLinus Torvalds } 22088814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2209222f1806SLuiz Capitulino if (err) 2210f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 22111da177e4SLinus Torvalds } 2212222f1806SLuiz Capitulino } else { 221368bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 221468bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr) 221568bf9f0bSAmerigo Wang + sizeof(struct udphdr) 221668bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 221768bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 221868bf9f0bSAmerigo Wang } 221968bf9f0bSAmerigo Wang 22201da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 22211da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 22221da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds struct in_device *in_dev; 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds rcu_read_lock(); 2227e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 22281da177e4SLinus Torvalds if (in_dev) { 22292638eb8bSFlorian Westphal const struct in_ifaddr *ifa; 22302638eb8bSFlorian Westphal 22312638eb8bSFlorian Westphal ifa = rcu_dereference(in_dev->ifa_list); 22322638eb8bSFlorian Westphal if (ifa) { 22332638eb8bSFlorian Westphal pkt_dev->saddr_min = ifa->ifa_address; 22341da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 22351da177e4SLinus Torvalds } 22361da177e4SLinus Torvalds } 22371da177e4SLinus Torvalds rcu_read_unlock(); 2238222f1806SLuiz Capitulino } else { 22391da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 22401da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 22411da177e4SLinus Torvalds } 22421da177e4SLinus Torvalds 22431da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 22441da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 22451da177e4SLinus Torvalds } 22461da177e4SLinus Torvalds /* Initialize current values. */ 224768bf9f0bSAmerigo Wang pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 224868bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size) 224968bf9f0bSAmerigo Wang pkt_dev->max_pkt_size = pkt_dev->min_pkt_size; 225068bf9f0bSAmerigo Wang 22511da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 22521da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 22531da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 22541da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 22551da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 22561da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 22571da177e4SLinus Torvalds pkt_dev->nflows = 0; 22581da177e4SLinus Torvalds } 22591da177e4SLinus Torvalds 22601da177e4SLinus Torvalds 2261fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2262fd29cf72SStephen Hemminger { 2263ef87979cSStephen Hemminger ktime_t start_time, end_time; 2264417bc4b8SEric Dumazet s64 remaining; 22652bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2266fd29cf72SStephen Hemminger 2267dbc1625fSSebastian Andrzej Siewior hrtimer_init_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 22682bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2269fd29cf72SStephen Hemminger 227043d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2271bcf91bdbSGuenter Roeck if (remaining <= 0) 2272bcf91bdbSGuenter Roeck goto out; 22732bc481cfSStephen Hemminger 2274398f382cSDaniel Borkmann start_time = ktime_get(); 227533136d12SEric Dumazet if (remaining < 100000) { 227633136d12SEric Dumazet /* for small delays (<100us), just loop until limit is reached */ 227733136d12SEric Dumazet do { 2278398f382cSDaniel Borkmann end_time = ktime_get(); 2279398f382cSDaniel Borkmann } while (ktime_compare(end_time, spin_until) < 0); 228033136d12SEric Dumazet } else { 22812bc481cfSStephen Hemminger do { 22822bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 22839dd8813eSThomas Gleixner hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_ABS); 22842bc481cfSStephen Hemminger 22852bc481cfSStephen Hemminger if (likely(t.task)) 22861da177e4SLinus Torvalds schedule(); 22871da177e4SLinus Torvalds 22882bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 22892bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 22902bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 2291398f382cSDaniel Borkmann end_time = ktime_get(); 229233136d12SEric Dumazet } 2293ef87979cSStephen Hemminger 2294ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 2295bcf91bdbSGuenter Roeck out: 229607a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 2297bcf91bdbSGuenter Roeck destroy_hrtimer_on_stack(&t.timer); 22981da177e4SLinus Torvalds } 22991da177e4SLinus Torvalds 230016dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 230116dab72fSJamal Hadi Salim { 230263d75463SPaolo Abeni pkt_dev->pkt_overhead = 0; 230316dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 230416dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 230516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 230616dab72fSJamal Hadi Salim } 230716dab72fSJamal Hadi Salim 2308648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2309007a531bSJamal Hadi Salim { 2310648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2311007a531bSJamal Hadi Salim } 2312007a531bSJamal Hadi Salim 2313007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2314007a531bSJamal Hadi Salim { 2315007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2316007a531bSJamal Hadi Salim 2317007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2318007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2319007a531bSJamal Hadi Salim /* reset time */ 2320007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 23211211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2322007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2323007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2324007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2325007a531bSJamal Hadi Salim } 2326007a531bSJamal Hadi Salim } else { 232733d7c5e5SAkinobu Mita flow = prandom_u32() % pkt_dev->cflows; 23281211a645SRobert Olsson pkt_dev->curfl = flow; 2329007a531bSJamal Hadi Salim 23301211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2331007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 23321211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 23331211a645SRobert Olsson } 2334007a531bSJamal Hadi Salim } 2335007a531bSJamal Hadi Salim 2336007a531bSJamal Hadi Salim return pkt_dev->curfl; 2337007a531bSJamal Hadi Salim } 2338007a531bSJamal Hadi Salim 2339a553e4a6SJamal Hadi Salim 2340a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2341a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2342a553e4a6SJamal Hadi Salim * we go look for it ... 2343a553e4a6SJamal Hadi Salim */ 2344bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2345fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2346a553e4a6SJamal Hadi Salim { 2347a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 23484e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); 2349a553e4a6SJamal Hadi Salim if (!x) { 2350c454997eSFan Du 2351c454997eSFan Du if (pkt_dev->spi) { 2352c454997eSFan Du /* We need as quick as possible to find the right SA 2353c454997eSFan Du * Searching with minimum criteria to archieve this. 2354c454997eSFan Du */ 2355c454997eSFan Du x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); 2356c454997eSFan Du } else { 2357a553e4a6SJamal Hadi Salim /* slow path: we dont already have xfrm_state */ 23587e652640SSteffen Klassert x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0, 23595447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2360a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2361a553e4a6SJamal Hadi Salim AF_INET, 2362a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2363a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2364c454997eSFan Du } 2365a553e4a6SJamal Hadi Salim if (x) { 2366a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2367a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2368a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2369a553e4a6SJamal Hadi Salim } 2370a553e4a6SJamal Hadi Salim 2371a553e4a6SJamal Hadi Salim } 2372a553e4a6SJamal Hadi Salim } 2373a553e4a6SJamal Hadi Salim #endif 2374fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2375fd2ea0a7SDavid S. Miller { 2376e6fce5b9SRobert Olsson 2377e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2378e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2379e6fce5b9SRobert Olsson 2380896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2381fd2ea0a7SDavid S. Miller __u16 t; 2382fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 238333d7c5e5SAkinobu Mita t = prandom_u32() % 2384fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2385fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2386fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2387fd2ea0a7SDavid S. Miller } else { 2388fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2389fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2390fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2391fd2ea0a7SDavid S. Miller } 2392fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2393fd2ea0a7SDavid S. Miller } 2394bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2395fd2ea0a7SDavid S. Miller } 2396fd2ea0a7SDavid S. Miller 23971da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 23981da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 23991da177e4SLinus Torvalds */ 2400222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2401222f1806SLuiz Capitulino { 24021da177e4SLinus Torvalds __u32 imn; 24031da177e4SLinus Torvalds __u32 imx; 24041da177e4SLinus Torvalds int flow = 0; 24051da177e4SLinus Torvalds 2406007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2407007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 24081da177e4SLinus Torvalds 24091da177e4SLinus Torvalds /* Deal with source MAC */ 24101da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 24111da177e4SLinus Torvalds __u32 mc; 24121da177e4SLinus Torvalds __u32 tmp; 24131da177e4SLinus Torvalds 24141da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 241533d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->src_mac_count; 24161da177e4SLinus Torvalds else { 24171da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2418ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2419222f1806SLuiz Capitulino pkt_dev->src_mac_count) 24201da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 24211da177e4SLinus Torvalds } 24221da177e4SLinus Torvalds 24231da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 24241da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 24251da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 24261da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 24271da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 24281da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 24291da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 24301da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 24311da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 24321da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 24331da177e4SLinus Torvalds } 24341da177e4SLinus Torvalds 24351da177e4SLinus Torvalds /* Deal with Destination MAC */ 24361da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 24371da177e4SLinus Torvalds __u32 mc; 24381da177e4SLinus Torvalds __u32 tmp; 24391da177e4SLinus Torvalds 24401da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 244133d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->dst_mac_count; 24421da177e4SLinus Torvalds 24431da177e4SLinus Torvalds else { 24441da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2445ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2446222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 24471da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 24481da177e4SLinus Torvalds } 24491da177e4SLinus Torvalds } 24501da177e4SLinus Torvalds 24511da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 24521da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 24531da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 24541da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 24551da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 24561da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 24571da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 24581da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 24591da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 24601da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 24611da177e4SLinus Torvalds } 24621da177e4SLinus Torvalds 2463ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 246495c96174SEric Dumazet unsigned int i; 2465ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2466ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2467ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 246833d7c5e5SAkinobu Mita ((__force __be32)prandom_u32() & 2469ca6549afSSteven Whitehouse htonl(0x000fffff)); 2470ca6549afSSteven Whitehouse } 2471ca6549afSSteven Whitehouse 247234954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 247333d7c5e5SAkinobu Mita pkt_dev->vlan_id = prandom_u32() & (4096 - 1); 247434954ddcSFrancesco Fondelli } 247534954ddcSFrancesco Fondelli 247634954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 247733d7c5e5SAkinobu Mita pkt_dev->svlan_id = prandom_u32() & (4096 - 1); 247834954ddcSFrancesco Fondelli } 247934954ddcSFrancesco Fondelli 24801da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 24811da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 248233d7c5e5SAkinobu Mita pkt_dev->cur_udp_src = prandom_u32() % 24835fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 24845fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 24851da177e4SLinus Torvalds 24861da177e4SLinus Torvalds else { 24871da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 24881da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 24891da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 24901da177e4SLinus Torvalds } 24911da177e4SLinus Torvalds } 24921da177e4SLinus Torvalds 24931da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 24941da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 249533d7c5e5SAkinobu Mita pkt_dev->cur_udp_dst = prandom_u32() % 24965fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 24975fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2498222f1806SLuiz Capitulino } else { 24991da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 25001da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 25011da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 25021da177e4SLinus Torvalds } 25031da177e4SLinus Torvalds } 25041da177e4SLinus Torvalds 25051da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 25061da177e4SLinus Torvalds 250763adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 250863adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 250963adc6fbSStephen Hemminger if (imn < imx) { 25101da177e4SLinus Torvalds __u32 t; 25111da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 251233d7c5e5SAkinobu Mita t = prandom_u32() % (imx - imn) + imn; 25131da177e4SLinus Torvalds else { 25141da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 25151da177e4SLinus Torvalds t++; 251663adc6fbSStephen Hemminger if (t > imx) 25171da177e4SLinus Torvalds t = imn; 251863adc6fbSStephen Hemminger 25191da177e4SLinus Torvalds } 25201da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 25211da177e4SLinus Torvalds } 25221da177e4SLinus Torvalds 2523007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 25241da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 25251da177e4SLinus Torvalds } else { 2526252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2527252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2528252e3346SAl Viro if (imn < imx) { 25291da177e4SLinus Torvalds __u32 t; 2530252e3346SAl Viro __be32 s; 25311da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 25321da177e4SLinus Torvalds 253370e3ba72SAkinobu Mita do { 253433d7c5e5SAkinobu Mita t = prandom_u32() % 253533d7c5e5SAkinobu Mita (imx - imn) + imn; 2536252e3346SAl Viro s = htonl(t); 253770e3ba72SAkinobu Mita } while (ipv4_is_loopback(s) || 253870e3ba72SAkinobu Mita ipv4_is_multicast(s) || 253970e3ba72SAkinobu Mita ipv4_is_lbcast(s) || 254070e3ba72SAkinobu Mita ipv4_is_zeronet(s) || 254170e3ba72SAkinobu Mita ipv4_is_local_multicast(s)); 2542252e3346SAl Viro pkt_dev->cur_daddr = s; 2543252e3346SAl Viro } else { 25441da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 25451da177e4SLinus Torvalds t++; 25461da177e4SLinus Torvalds if (t > imx) { 25471da177e4SLinus Torvalds t = imn; 25481da177e4SLinus Torvalds } 25491da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 25501da177e4SLinus Torvalds } 25511da177e4SLinus Torvalds } 25521da177e4SLinus Torvalds if (pkt_dev->cflows) { 2553007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2554222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2555222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2556a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 25576f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) 2558a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2559a553e4a6SJamal Hadi Salim #endif 25601da177e4SLinus Torvalds pkt_dev->nflows++; 25611da177e4SLinus Torvalds } 25621da177e4SLinus Torvalds } 2563222f1806SLuiz Capitulino } else { /* IPV6 * */ 2564222f1806SLuiz Capitulino 256506e30411SJoe Perches if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) { 25661da177e4SLinus Torvalds int i; 25671da177e4SLinus Torvalds 25681da177e4SLinus Torvalds /* Only random destinations yet */ 25691da177e4SLinus Torvalds 25701da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 25711da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 257233d7c5e5SAkinobu Mita (((__force __be32)prandom_u32() | 25731da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 25741da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 25751da177e4SLinus Torvalds } 25761da177e4SLinus Torvalds } 25771da177e4SLinus Torvalds } 25781da177e4SLinus Torvalds 25791da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 25801da177e4SLinus Torvalds __u32 t; 25811da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 258233d7c5e5SAkinobu Mita t = prandom_u32() % 25835fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 25845fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2585222f1806SLuiz Capitulino } else { 25861da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 25871da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 25881da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 25891da177e4SLinus Torvalds } 25901da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 259190149031SNick Richardson } else if (pkt_dev->n_imix_entries > 0) { 259290149031SNick Richardson struct imix_pkt *entry; 259390149031SNick Richardson __u32 t = prandom_u32() % IMIX_PRECISION; 259490149031SNick Richardson __u8 entry_index = pkt_dev->imix_distribution[t]; 259590149031SNick Richardson 259690149031SNick Richardson entry = &pkt_dev->imix_entries[entry_index]; 259790149031SNick Richardson entry->count_so_far++; 259890149031SNick Richardson pkt_dev->cur_pkt_size = entry->size; 25991da177e4SLinus Torvalds } 26001da177e4SLinus Torvalds 2601fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 260245b270f8SRobert Olsson 26031da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 26041da177e4SLinus Torvalds } 26051da177e4SLinus Torvalds 26067e5a3ef6SNick Richardson static void fill_imix_distribution(struct pktgen_dev *pkt_dev) 26077e5a3ef6SNick Richardson { 26087e5a3ef6SNick Richardson int cumulative_probabilites[MAX_IMIX_ENTRIES]; 26097e5a3ef6SNick Richardson int j = 0; 26107e5a3ef6SNick Richardson __u64 cumulative_prob = 0; 26117e5a3ef6SNick Richardson __u64 total_weight = 0; 26127e5a3ef6SNick Richardson int i = 0; 26137e5a3ef6SNick Richardson 26147e5a3ef6SNick Richardson for (i = 0; i < pkt_dev->n_imix_entries; i++) 26157e5a3ef6SNick Richardson total_weight += pkt_dev->imix_entries[i].weight; 26167e5a3ef6SNick Richardson 26177e5a3ef6SNick Richardson /* Fill cumulative_probabilites with sum of normalized probabilities */ 26187e5a3ef6SNick Richardson for (i = 0; i < pkt_dev->n_imix_entries - 1; i++) { 26197e5a3ef6SNick Richardson cumulative_prob += div64_u64(pkt_dev->imix_entries[i].weight * 26207e5a3ef6SNick Richardson IMIX_PRECISION, 26217e5a3ef6SNick Richardson total_weight); 26227e5a3ef6SNick Richardson cumulative_probabilites[i] = cumulative_prob; 26237e5a3ef6SNick Richardson } 26247e5a3ef6SNick Richardson cumulative_probabilites[pkt_dev->n_imix_entries - 1] = 100; 26257e5a3ef6SNick Richardson 26267e5a3ef6SNick Richardson for (i = 0; i < IMIX_PRECISION; i++) { 26277e5a3ef6SNick Richardson if (i == cumulative_probabilites[j]) 26287e5a3ef6SNick Richardson j++; 26297e5a3ef6SNick Richardson pkt_dev->imix_distribution[i] = j; 26307e5a3ef6SNick Richardson } 26317e5a3ef6SNick Richardson } 2632a553e4a6SJamal Hadi Salim 2633a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 26345537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { 2635cf93d47eSFan Du 2636cf93d47eSFan Du [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ 2637cf93d47eSFan Du }; 2638cf93d47eSFan Du 2639a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2640a553e4a6SJamal Hadi Salim { 2641a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2642a553e4a6SJamal Hadi Salim int err = 0; 26436de9ace4SFan Du struct net *net = dev_net(pkt_dev->odev); 2644a553e4a6SJamal Hadi Salim 2645a553e4a6SJamal Hadi Salim if (!x) 2646a553e4a6SJamal Hadi Salim return 0; 2647a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2648a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2649cf93d47eSFan Du if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) 2650a553e4a6SJamal Hadi Salim return 0; 2651a553e4a6SJamal Hadi Salim 2652cf93d47eSFan Du /* But when user specify an valid SPI, transformation 2653cf93d47eSFan Du * supports both transport/tunnel mode + ESP/AH type. 2654cf93d47eSFan Du */ 2655cf93d47eSFan Du if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) 2656b6ca8bd5SDavid Miller skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF; 2657cf93d47eSFan Du 2658cf93d47eSFan Du rcu_read_lock_bh(); 26590c620e97SFlorian Westphal err = pktgen_xfrm_outer_mode_output(x, skb); 2660cf93d47eSFan Du rcu_read_unlock_bh(); 26616de9ace4SFan Du if (err) { 26626de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); 2663a553e4a6SJamal Hadi Salim goto error; 26646de9ace4SFan Du } 2665a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 26666de9ace4SFan Du if (err) { 26676de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); 2668a553e4a6SJamal Hadi Salim goto error; 26696de9ace4SFan Du } 26700af0a413SFan Du spin_lock_bh(&x->lock); 2671a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2672a553e4a6SJamal Hadi Salim x->curlft.packets++; 26730af0a413SFan Du spin_unlock_bh(&x->lock); 2674a553e4a6SJamal Hadi Salim error: 2675a553e4a6SJamal Hadi Salim return err; 2676a553e4a6SJamal Hadi Salim } 2677a553e4a6SJamal Hadi Salim 2678475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2679a553e4a6SJamal Hadi Salim { 2680a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2681a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2682d6182223SPaul Gortmaker int i; 2683d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2684a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2685a553e4a6SJamal Hadi Salim if (x) { 2686a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2687a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2688a553e4a6SJamal Hadi Salim } 2689a553e4a6SJamal Hadi Salim } 2690a553e4a6SJamal Hadi Salim } 2691a553e4a6SJamal Hadi Salim } 2692a553e4a6SJamal Hadi Salim 2693475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2694a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2695a553e4a6SJamal Hadi Salim { 26966f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) { 2697a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2698a553e4a6SJamal Hadi Salim int nhead = 0; 2699a553e4a6SJamal Hadi Salim if (x) { 2700d4969581SEric Dumazet struct ethhdr *eth; 27013868204dSfan.du struct iphdr *iph; 2702d4969581SEric Dumazet int ret; 27033868204dSfan.du 2704a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2705a553e4a6SJamal Hadi Salim if (nhead > 0) { 2706a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2707a553e4a6SJamal Hadi Salim if (ret < 0) { 2708f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2709f9467eaeSJoe Perches ret); 2710b4bb4ac8SIlpo Järvinen goto err; 2711a553e4a6SJamal Hadi Salim } 2712a553e4a6SJamal Hadi Salim } 2713a553e4a6SJamal Hadi Salim 2714a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2715a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2716a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2717a553e4a6SJamal Hadi Salim if (ret) { 2718f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2719b4bb4ac8SIlpo Järvinen goto err; 2720a553e4a6SJamal Hadi Salim } 2721a553e4a6SJamal Hadi Salim /* restore ll */ 2722d58ff351SJohannes Berg eth = skb_push(skb, ETH_HLEN); 2723d4969581SEric Dumazet memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN); 2724d4969581SEric Dumazet eth->h_proto = protocol; 27253868204dSfan.du 27263868204dSfan.du /* Update IPv4 header len as well as checksum value */ 27273868204dSfan.du iph = ip_hdr(skb); 27283868204dSfan.du iph->tot_len = htons(skb->len - ETH_HLEN); 27293868204dSfan.du ip_send_check(iph); 2730a553e4a6SJamal Hadi Salim } 2731a553e4a6SJamal Hadi Salim } 2732a553e4a6SJamal Hadi Salim return 1; 2733b4bb4ac8SIlpo Järvinen err: 2734b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2735b4bb4ac8SIlpo Järvinen return 0; 2736a553e4a6SJamal Hadi Salim } 2737a553e4a6SJamal Hadi Salim #endif 2738a553e4a6SJamal Hadi Salim 2739ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2740ca6549afSSteven Whitehouse { 274195c96174SEric Dumazet unsigned int i; 274263adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2743ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 274463adc6fbSStephen Hemminger 2745ca6549afSSteven Whitehouse mpls--; 2746ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2747ca6549afSSteven Whitehouse } 2748ca6549afSSteven Whitehouse 27490f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 27500f37c605SAl Viro unsigned int prio) 27510f37c605SAl Viro { 27520f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 27530f37c605SAl Viro } 27540f37c605SAl Viro 275526ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, 275626ad7879SEric Dumazet int datalen) 275726ad7879SEric Dumazet { 27587f5d3f27SArnd Bergmann struct timespec64 timestamp; 275926ad7879SEric Dumazet struct pktgen_hdr *pgh; 276026ad7879SEric Dumazet 27614df864c1SJohannes Berg pgh = skb_put(skb, sizeof(*pgh)); 276226ad7879SEric Dumazet datalen -= sizeof(*pgh); 276326ad7879SEric Dumazet 276426ad7879SEric Dumazet if (pkt_dev->nfrags <= 0) { 2765b080db58SJohannes Berg skb_put_zero(skb, datalen); 276626ad7879SEric Dumazet } else { 276726ad7879SEric Dumazet int frags = pkt_dev->nfrags; 276826ad7879SEric Dumazet int i, len; 27697d36a991Samit salecha int frag_len; 277026ad7879SEric Dumazet 277126ad7879SEric Dumazet 277226ad7879SEric Dumazet if (frags > MAX_SKB_FRAGS) 277326ad7879SEric Dumazet frags = MAX_SKB_FRAGS; 277426ad7879SEric Dumazet len = datalen - frags * PAGE_SIZE; 277526ad7879SEric Dumazet if (len > 0) { 2776b080db58SJohannes Berg skb_put_zero(skb, len); 277726ad7879SEric Dumazet datalen = frags * PAGE_SIZE; 277826ad7879SEric Dumazet } 277926ad7879SEric Dumazet 278026ad7879SEric Dumazet i = 0; 2781dc91e3beSDavid S. Miller frag_len = (datalen/frags) < PAGE_SIZE ? 2782dc91e3beSDavid S. Miller (datalen/frags) : PAGE_SIZE; 278326ad7879SEric Dumazet while (datalen > 0) { 278426ad7879SEric Dumazet if (unlikely(!pkt_dev->page)) { 278526ad7879SEric Dumazet int node = numa_node_id(); 278626ad7879SEric Dumazet 278726ad7879SEric Dumazet if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE)) 278826ad7879SEric Dumazet node = pkt_dev->node; 278926ad7879SEric Dumazet pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); 279026ad7879SEric Dumazet if (!pkt_dev->page) 279126ad7879SEric Dumazet break; 279226ad7879SEric Dumazet } 2793a0bec1cdSIan Campbell get_page(pkt_dev->page); 2794ea2ab693SIan Campbell skb_frag_set_page(skb, i, pkt_dev->page); 2795b54c9d5bSJonathan Lemon skb_frag_off_set(&skb_shinfo(skb)->frags[i], 0); 27967d36a991Samit salecha /*last fragment, fill rest of data*/ 27977d36a991Samit salecha if (i == (frags - 1)) 27989e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], 2799dc91e3beSDavid S. Miller (datalen < PAGE_SIZE ? datalen : PAGE_SIZE)); 28007d36a991Samit salecha else 28019e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len); 28029e903e08SEric Dumazet datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]); 28039e903e08SEric Dumazet skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 28049e903e08SEric Dumazet skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 280526ad7879SEric Dumazet i++; 280626ad7879SEric Dumazet skb_shinfo(skb)->nr_frags = i; 280726ad7879SEric Dumazet } 280826ad7879SEric Dumazet } 280926ad7879SEric Dumazet 281026ad7879SEric Dumazet /* Stamp the time, and sequence number, 281126ad7879SEric Dumazet * convert them to network byte order 281226ad7879SEric Dumazet */ 281326ad7879SEric Dumazet pgh->pgh_magic = htonl(PKTGEN_MAGIC); 281426ad7879SEric Dumazet pgh->seq_num = htonl(pkt_dev->seq_num); 281526ad7879SEric Dumazet 2816afb84b62SJesper Dangaard Brouer if (pkt_dev->flags & F_NO_TIMESTAMP) { 2817afb84b62SJesper Dangaard Brouer pgh->tv_sec = 0; 2818afb84b62SJesper Dangaard Brouer pgh->tv_usec = 0; 2819afb84b62SJesper Dangaard Brouer } else { 28207f5d3f27SArnd Bergmann /* 28217f5d3f27SArnd Bergmann * pgh->tv_sec wraps in y2106 when interpreted as unsigned 28227f5d3f27SArnd Bergmann * as done by wireshark, or y2038 when interpreted as signed. 28237f5d3f27SArnd Bergmann * This is probably harmless, but if anyone wants to improve 28247f5d3f27SArnd Bergmann * it, we could introduce a variant that puts 64-bit nanoseconds 28257f5d3f27SArnd Bergmann * into the respective header bytes. 28267f5d3f27SArnd Bergmann * This would also be slightly faster to read. 28277f5d3f27SArnd Bergmann */ 28287f5d3f27SArnd Bergmann ktime_get_real_ts64(×tamp); 282926ad7879SEric Dumazet pgh->tv_sec = htonl(timestamp.tv_sec); 28307f5d3f27SArnd Bergmann pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC); 283126ad7879SEric Dumazet } 2832afb84b62SJesper Dangaard Brouer } 283326ad7879SEric Dumazet 28347a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev, 283563d75463SPaolo Abeni struct pktgen_dev *pkt_dev) 28367a6e288dSDaniel Borkmann { 283763d75463SPaolo Abeni unsigned int extralen = LL_RESERVED_SPACE(dev); 28387a6e288dSDaniel Borkmann struct sk_buff *skb = NULL; 283963d75463SPaolo Abeni unsigned int size; 28407a6e288dSDaniel Borkmann 284163d75463SPaolo Abeni size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead; 28427a6e288dSDaniel Borkmann if (pkt_dev->flags & F_NODE) { 28437a6e288dSDaniel Borkmann int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id(); 28447a6e288dSDaniel Borkmann 28457a6e288dSDaniel Borkmann skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node); 28467a6e288dSDaniel Borkmann if (likely(skb)) { 28477a6e288dSDaniel Borkmann skb_reserve(skb, NET_SKB_PAD); 28487a6e288dSDaniel Borkmann skb->dev = dev; 28497a6e288dSDaniel Borkmann } 28507a6e288dSDaniel Borkmann } else { 28517a6e288dSDaniel Borkmann skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT); 28527a6e288dSDaniel Borkmann } 28533de03596SJohn Fastabend 285463d75463SPaolo Abeni /* the caller pre-fetches from skb->data and reserves for the mac hdr */ 28553de03596SJohn Fastabend if (likely(skb)) 285663d75463SPaolo Abeni skb_reserve(skb, extralen - 16); 28577a6e288dSDaniel Borkmann 28587a6e288dSDaniel Borkmann return skb; 28597a6e288dSDaniel Borkmann } 28607a6e288dSDaniel Borkmann 28611da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 28621da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 28631da177e4SLinus Torvalds { 28641da177e4SLinus Torvalds struct sk_buff *skb = NULL; 28651da177e4SLinus Torvalds __u8 *eth; 28661da177e4SLinus Torvalds struct udphdr *udph; 28671da177e4SLinus Torvalds int datalen, iplen; 28681da177e4SLinus Torvalds struct iphdr *iph; 2869d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2870ca6549afSSteven Whitehouse __be32 *mpls; 287134954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 287234954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 287334954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 287434954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2875fd2ea0a7SDavid S. Miller u16 queue_map; 2876ca6549afSSteven Whitehouse 2877ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2878d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 28791da177e4SLinus Torvalds 288034954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2881d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 288234954ddcSFrancesco Fondelli 288364053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 288464053beeSRobert Olsson * fields. 288564053beeSRobert Olsson */ 288664053beeSRobert Olsson mod_cur_headers(pkt_dev); 2887eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 288864053beeSRobert Olsson 288963d75463SPaolo Abeni skb = pktgen_alloc_skb(odev, pkt_dev); 28901da177e4SLinus Torvalds if (!skb) { 28911da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 28921da177e4SLinus Torvalds return NULL; 28931da177e4SLinus Torvalds } 28941da177e4SLinus Torvalds 28957a6e288dSDaniel Borkmann prefetchw(skb->data); 289663d75463SPaolo Abeni skb_reserve(skb, 16); 28971da177e4SLinus Torvalds 28981da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 2899d58ff351SJohannes Berg eth = skb_push(skb, 14); 29004df864c1SJohannes Berg mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 2901ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2902ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 290334954ddcSFrancesco Fondelli 290434954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 290534954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 29064df864c1SJohannes Berg svlan_tci = skb_put(skb, sizeof(__be16)); 29070f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 29080f37c605SAl Viro pkt_dev->svlan_cfi, 29090f37c605SAl Viro pkt_dev->svlan_p); 29104df864c1SJohannes Berg svlan_encapsulated_proto = skb_put(skb, 29114df864c1SJohannes Berg sizeof(__be16)); 2912d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 291334954ddcSFrancesco Fondelli } 29144df864c1SJohannes Berg vlan_tci = skb_put(skb, sizeof(__be16)); 29150f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 29160f37c605SAl Viro pkt_dev->vlan_cfi, 29170f37c605SAl Viro pkt_dev->vlan_p); 29184df864c1SJohannes Berg vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 2919d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 292034954ddcSFrancesco Fondelli } 292134954ddcSFrancesco Fondelli 2922c145aeb3SZhang Shengju skb_reset_mac_header(skb); 2923525cebedSThomas Graf skb_set_network_header(skb, skb->len); 29244df864c1SJohannes Berg iph = skb_put(skb, sizeof(struct iphdr)); 2925525cebedSThomas Graf 2926525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 29274df864c1SJohannes Berg udph = skb_put(skb, sizeof(struct udphdr)); 2928fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 29299e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 29309e50e3acSJohn Fastabend 29311da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2932252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 29331da177e4SLinus Torvalds 2934ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2935ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 293616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 29376af773e7SNishank Trivedi if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) 29381da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 29391da177e4SLinus Torvalds 29401da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 29411da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 29421da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 2943c26bf4a5SThomas Graf udph->check = 0; 29441da177e4SLinus Torvalds 29451da177e4SLinus Torvalds iph->ihl = 5; 29461da177e4SLinus Torvalds iph->version = 4; 29471da177e4SLinus Torvalds iph->ttl = 32; 29481ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 29491da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 29501da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 29511da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 295266ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 295366ed1e5eSEric Dumazet pkt_dev->ip_id++; 29541da177e4SLinus Torvalds iph->frag_off = 0; 29551da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 29561da177e4SLinus Torvalds iph->tot_len = htons(iplen); 295703c633e7SThomas Graf ip_send_check(iph); 2958ca6549afSSteven Whitehouse skb->protocol = protocol; 29591da177e4SLinus Torvalds skb->dev = odev; 29601da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 2961c26bf4a5SThomas Graf 29627744b5f3SSabrina Dubroca pktgen_finalize_skb(pkt_dev, skb, datalen); 29637744b5f3SSabrina Dubroca 2964c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 2965c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 2966c8cd0989STom Herbert } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) { 2967c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 2968c26bf4a5SThomas Graf skb->csum = 0; 29697744b5f3SSabrina Dubroca udp4_hwcsum(skb, iph->saddr, iph->daddr); 2970c26bf4a5SThomas Graf } else { 29717744b5f3SSabrina Dubroca __wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0); 2972c26bf4a5SThomas Graf 2973c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 29747744b5f3SSabrina Dubroca udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 2975c26bf4a5SThomas Graf datalen + 8, IPPROTO_UDP, csum); 2976c26bf4a5SThomas Graf 2977c26bf4a5SThomas Graf if (udph->check == 0) 2978c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 2979c26bf4a5SThomas Graf } 2980c26bf4a5SThomas Graf 2981a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2982a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2983a553e4a6SJamal Hadi Salim return NULL; 2984a553e4a6SJamal Hadi Salim #endif 2985a553e4a6SJamal Hadi Salim 29861da177e4SLinus Torvalds return skb; 29871da177e4SLinus Torvalds } 29881da177e4SLinus Torvalds 29891da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 29901da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29911da177e4SLinus Torvalds { 29921da177e4SLinus Torvalds struct sk_buff *skb = NULL; 29931da177e4SLinus Torvalds __u8 *eth; 29941da177e4SLinus Torvalds struct udphdr *udph; 2995c26bf4a5SThomas Graf int datalen, udplen; 29961da177e4SLinus Torvalds struct ipv6hdr *iph; 2997d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2998ca6549afSSteven Whitehouse __be32 *mpls; 299934954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 300034954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 300134954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 300234954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 3003fd2ea0a7SDavid S. Miller u16 queue_map; 3004ca6549afSSteven Whitehouse 3005ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 3006d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 30071da177e4SLinus Torvalds 300834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 3009d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 301034954ddcSFrancesco Fondelli 301164053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 301264053beeSRobert Olsson * fields. 301364053beeSRobert Olsson */ 301464053beeSRobert Olsson mod_cur_headers(pkt_dev); 3015eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 301664053beeSRobert Olsson 301763d75463SPaolo Abeni skb = pktgen_alloc_skb(odev, pkt_dev); 30181da177e4SLinus Torvalds if (!skb) { 30191da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 30201da177e4SLinus Torvalds return NULL; 30211da177e4SLinus Torvalds } 30221da177e4SLinus Torvalds 30237a6e288dSDaniel Borkmann prefetchw(skb->data); 30241da177e4SLinus Torvalds skb_reserve(skb, 16); 30251da177e4SLinus Torvalds 30261da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 3027d58ff351SJohannes Berg eth = skb_push(skb, 14); 30284df864c1SJohannes Berg mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 3029ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 3030ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 303134954ddcSFrancesco Fondelli 303234954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 303334954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 30344df864c1SJohannes Berg svlan_tci = skb_put(skb, sizeof(__be16)); 30350f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 30360f37c605SAl Viro pkt_dev->svlan_cfi, 30370f37c605SAl Viro pkt_dev->svlan_p); 30384df864c1SJohannes Berg svlan_encapsulated_proto = skb_put(skb, 30394df864c1SJohannes Berg sizeof(__be16)); 3040d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 304134954ddcSFrancesco Fondelli } 30424df864c1SJohannes Berg vlan_tci = skb_put(skb, sizeof(__be16)); 30430f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 30440f37c605SAl Viro pkt_dev->vlan_cfi, 30450f37c605SAl Viro pkt_dev->vlan_p); 30464df864c1SJohannes Berg vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 3047d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 304834954ddcSFrancesco Fondelli } 304934954ddcSFrancesco Fondelli 3050c145aeb3SZhang Shengju skb_reset_mac_header(skb); 3051525cebedSThomas Graf skb_set_network_header(skb, skb->len); 30524df864c1SJohannes Berg iph = skb_put(skb, sizeof(struct ipv6hdr)); 3053525cebedSThomas Graf 3054525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 30554df864c1SJohannes Berg udph = skb_put(skb, sizeof(struct udphdr)); 3056fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 30579e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 30581da177e4SLinus Torvalds 30591da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 3060252e3346SAl Viro *(__be16 *) ð[12] = protocol; 30611da177e4SLinus Torvalds 3062ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 3063ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 3064ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 306516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 30661da177e4SLinus Torvalds 30675aa8b572SAmerigo Wang if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { 30681da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 3069e87cc472SJoe Perches net_info_ratelimited("increased datalen to %d\n", datalen); 30701da177e4SLinus Torvalds } 30711da177e4SLinus Torvalds 3072c26bf4a5SThomas Graf udplen = datalen + sizeof(struct udphdr); 30731da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 30741da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 3075c26bf4a5SThomas Graf udph->len = htons(udplen); 3076c26bf4a5SThomas Graf udph->check = 0; 30771da177e4SLinus Torvalds 3078d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 30791da177e4SLinus Torvalds 30801ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 30811ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 3082252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 30831ca7768cSFrancesco Fondelli } 30841ca7768cSFrancesco Fondelli 30851da177e4SLinus Torvalds iph->hop_limit = 32; 30861da177e4SLinus Torvalds 3087c26bf4a5SThomas Graf iph->payload_len = htons(udplen); 30881da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 30891da177e4SLinus Torvalds 30904e3fd7a0SAlexey Dobriyan iph->daddr = pkt_dev->cur_in6_daddr; 30914e3fd7a0SAlexey Dobriyan iph->saddr = pkt_dev->cur_in6_saddr; 30921da177e4SLinus Torvalds 3093ca6549afSSteven Whitehouse skb->protocol = protocol; 30941da177e4SLinus Torvalds skb->dev = odev; 30951da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 30961da177e4SLinus Torvalds 30977744b5f3SSabrina Dubroca pktgen_finalize_skb(pkt_dev, skb, datalen); 30987744b5f3SSabrina Dubroca 3099c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 3100c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 3101c8cd0989STom Herbert } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) { 3102c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 3103c26bf4a5SThomas Graf skb->csum_start = skb_transport_header(skb) - skb->head; 3104c26bf4a5SThomas Graf skb->csum_offset = offsetof(struct udphdr, check); 3105c26bf4a5SThomas Graf udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0); 3106c26bf4a5SThomas Graf } else { 31077744b5f3SSabrina Dubroca __wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0); 3108c26bf4a5SThomas Graf 3109c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 3110c26bf4a5SThomas Graf udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum); 3111c26bf4a5SThomas Graf 3112c26bf4a5SThomas Graf if (udph->check == 0) 3113c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 3114c26bf4a5SThomas Graf } 3115c26bf4a5SThomas Graf 31161da177e4SLinus Torvalds return skb; 31171da177e4SLinus Torvalds } 31181da177e4SLinus Torvalds 3119475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 31201da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 31211da177e4SLinus Torvalds { 31221da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 31231da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 31241da177e4SLinus Torvalds else 31251da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 31261da177e4SLinus Torvalds } 31271da177e4SLinus Torvalds 31281da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 31291da177e4SLinus Torvalds { 31301da177e4SLinus Torvalds pkt_dev->seq_num = 1; 31311da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 31321da177e4SLinus Torvalds pkt_dev->sofar = 0; 31331da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 31341da177e4SLinus Torvalds pkt_dev->errors = 0; 31351da177e4SLinus Torvalds } 31361da177e4SLinus Torvalds 31371da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 31381da177e4SLinus Torvalds 31391da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 31401da177e4SLinus Torvalds { 3141c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 31421da177e4SLinus Torvalds int started = 0; 31431da177e4SLinus Torvalds 3144f9467eaeSJoe Perches func_enter(); 31451da177e4SLinus Torvalds 31468788370aSJesper Dangaard Brouer rcu_read_lock(); 31478788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 31481da177e4SLinus Torvalds 31491da177e4SLinus Torvalds /* 31501da177e4SLinus Torvalds * setup odev and create initial packet. 31511da177e4SLinus Torvalds */ 31521da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 31531da177e4SLinus Torvalds 31541da177e4SLinus Torvalds if (pkt_dev->odev) { 31551da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 31561da177e4SLinus Torvalds pkt_dev->skb = NULL; 3157398f382cSDaniel Borkmann pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); 3158fd29cf72SStephen Hemminger 315916dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 31601da177e4SLinus Torvalds 31611da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 31628788370aSJesper Dangaard Brouer pkt_dev->running = 1; /* Cranke yeself! */ 31631da177e4SLinus Torvalds started++; 3164222f1806SLuiz Capitulino } else 31651da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 31661da177e4SLinus Torvalds } 31678788370aSJesper Dangaard Brouer rcu_read_unlock(); 3168222f1806SLuiz Capitulino if (started) 3169222f1806SLuiz Capitulino t->control &= ~(T_STOP); 31701da177e4SLinus Torvalds } 31711da177e4SLinus Torvalds 3172cda9de0bSYejune Deng static void pktgen_handle_all_threads(struct pktgen_net *pn, u32 flags) 31731da177e4SLinus Torvalds { 3174cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31751da177e4SLinus Torvalds 31766146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3177cdcdbe0bSLuiz Capitulino 31784e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 3179cda9de0bSYejune Deng t->control |= (flags); 3180cdcdbe0bSLuiz Capitulino 31816146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 31821da177e4SLinus Torvalds } 31831da177e4SLinus Torvalds 3184cda9de0bSYejune Deng static void pktgen_stop_all_threads(struct pktgen_net *pn) 3185cda9de0bSYejune Deng { 3186cda9de0bSYejune Deng func_enter(); 3187cda9de0bSYejune Deng 3188cda9de0bSYejune Deng pktgen_handle_all_threads(pn, T_STOP); 3189cda9de0bSYejune Deng } 3190cda9de0bSYejune Deng 3191648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 31921da177e4SLinus Torvalds { 3193648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 31941da177e4SLinus Torvalds 31958788370aSJesper Dangaard Brouer rcu_read_lock(); 31968788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 31978788370aSJesper Dangaard Brouer if (pkt_dev->running) { 31988788370aSJesper Dangaard Brouer rcu_read_unlock(); 3199648fda74SStephen Hemminger return 1; 32008788370aSJesper Dangaard Brouer } 32018788370aSJesper Dangaard Brouer rcu_read_unlock(); 3202648fda74SStephen Hemminger return 0; 32031da177e4SLinus Torvalds } 32041da177e4SLinus Torvalds 32051da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 32061da177e4SLinus Torvalds { 32071da177e4SLinus Torvalds while (thread_is_running(t)) { 32081da177e4SLinus Torvalds 3209720f1de4SPaolo Abeni /* note: 't' will still be around even after the unlock/lock 3210720f1de4SPaolo Abeni * cycle because pktgen_thread threads are only cleared at 3211720f1de4SPaolo Abeni * net exit 3212720f1de4SPaolo Abeni */ 3213720f1de4SPaolo Abeni mutex_unlock(&pktgen_thread_lock); 32141da177e4SLinus Torvalds msleep_interruptible(100); 3215720f1de4SPaolo Abeni mutex_lock(&pktgen_thread_lock); 32161da177e4SLinus Torvalds 32171da177e4SLinus Torvalds if (signal_pending(current)) 32181da177e4SLinus Torvalds goto signal; 32191da177e4SLinus Torvalds } 32201da177e4SLinus Torvalds return 1; 32211da177e4SLinus Torvalds signal: 32221da177e4SLinus Torvalds return 0; 32231da177e4SLinus Torvalds } 32241da177e4SLinus Torvalds 32254e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn) 32261da177e4SLinus Torvalds { 3227cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32281da177e4SLinus Torvalds int sig = 1; 32291da177e4SLinus Torvalds 3230720f1de4SPaolo Abeni /* prevent from racing with rmmod */ 3231720f1de4SPaolo Abeni if (!try_module_get(THIS_MODULE)) 3232720f1de4SPaolo Abeni return sig; 3233720f1de4SPaolo Abeni 32346146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3235cdcdbe0bSLuiz Capitulino 32364e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 32371da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3238222f1806SLuiz Capitulino if (sig == 0) 3239222f1806SLuiz Capitulino break; 32401da177e4SLinus Torvalds } 3241cdcdbe0bSLuiz Capitulino 3242cdcdbe0bSLuiz Capitulino if (sig == 0) 32434e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 32441da177e4SLinus Torvalds t->control |= (T_STOP); 3245cdcdbe0bSLuiz Capitulino 32466146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 3247720f1de4SPaolo Abeni module_put(THIS_MODULE); 32481da177e4SLinus Torvalds return sig; 32491da177e4SLinus Torvalds } 32501da177e4SLinus Torvalds 32514e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn) 32521da177e4SLinus Torvalds { 3253f9467eaeSJoe Perches func_enter(); 32541da177e4SLinus Torvalds 3255cda9de0bSYejune Deng pktgen_handle_all_threads(pn, T_RUN); 32561da177e4SLinus Torvalds 325763adc6fbSStephen Hemminger /* Propagate thread->control */ 325863adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 32591da177e4SLinus Torvalds 32604e58a027SCong Wang pktgen_wait_all_threads_run(pn); 32611da177e4SLinus Torvalds } 32621da177e4SLinus Torvalds 32634e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn) 3264eb37b41cSJesse Brandeburg { 3265f9467eaeSJoe Perches func_enter(); 3266eb37b41cSJesse Brandeburg 3267cda9de0bSYejune Deng pktgen_handle_all_threads(pn, T_REMDEVALL); 3268eb37b41cSJesse Brandeburg 326963adc6fbSStephen Hemminger /* Propagate thread->control */ 327063adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3271eb37b41cSJesse Brandeburg 32724e58a027SCong Wang pktgen_wait_all_threads_run(pn); 3273eb37b41cSJesse Brandeburg } 3274eb37b41cSJesse Brandeburg 32751da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 32761da177e4SLinus Torvalds { 3277fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 32781da177e4SLinus Torvalds char *p = pkt_dev->result; 3279fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3280fd29cf72SStephen Hemminger pkt_dev->started_at); 3281fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 32821da177e4SLinus Torvalds 328303a14ab1SDaniel Turull p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 3284fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3285fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3286fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 32871da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 32881da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 32891da177e4SLinus Torvalds 3290fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3291fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 32921da177e4SLinus Torvalds 3293769afb3fSNick Richardson if (pkt_dev->n_imix_entries > 0) { 3294769afb3fSNick Richardson int i; 3295769afb3fSNick Richardson struct imix_pkt *entry; 3296769afb3fSNick Richardson 3297769afb3fSNick Richardson bps = 0; 3298769afb3fSNick Richardson for (i = 0; i < pkt_dev->n_imix_entries; i++) { 3299769afb3fSNick Richardson entry = &pkt_dev->imix_entries[i]; 3300769afb3fSNick Richardson bps += entry->size * entry->count_so_far; 3301769afb3fSNick Richardson } 3302769afb3fSNick Richardson bps = div64_u64(bps * 8 * NSEC_PER_SEC, ktime_to_ns(elapsed)); 3303769afb3fSNick Richardson } else { 33041da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 3305769afb3fSNick Richardson } 33061da177e4SLinus Torvalds 33071da177e4SLinus Torvalds mbps = bps; 33081da177e4SLinus Torvalds do_div(mbps, 1000000); 33091da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 33101da177e4SLinus Torvalds (unsigned long long)pps, 33111da177e4SLinus Torvalds (unsigned long long)mbps, 33121da177e4SLinus Torvalds (unsigned long long)bps, 33131da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 33141da177e4SLinus Torvalds } 33151da177e4SLinus Torvalds 33161da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 33171da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 33181da177e4SLinus Torvalds { 3319222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 33201da177e4SLinus Torvalds 33211da177e4SLinus Torvalds if (!pkt_dev->running) { 3322294a0b7fSJoe Perches pr_warn("interface: %s is already stopped\n", 3323f9467eaeSJoe Perches pkt_dev->odevname); 33241da177e4SLinus Torvalds return -EINVAL; 33251da177e4SLinus Torvalds } 33261da177e4SLinus Torvalds 33278788370aSJesper Dangaard Brouer pkt_dev->running = 0; 33283bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 33293bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3330398f382cSDaniel Borkmann pkt_dev->stopped_at = ktime_get(); 33311da177e4SLinus Torvalds 333295ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 33331da177e4SLinus Torvalds 33341da177e4SLinus Torvalds return 0; 33351da177e4SLinus Torvalds } 33361da177e4SLinus Torvalds 33371da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 33381da177e4SLinus Torvalds { 3339c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 33401da177e4SLinus Torvalds 33418788370aSJesper Dangaard Brouer rcu_read_lock(); 33428788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3343c26a8016SLuiz Capitulino if (!pkt_dev->running) 3344222f1806SLuiz Capitulino continue; 3345222f1806SLuiz Capitulino if (best == NULL) 3346c26a8016SLuiz Capitulino best = pkt_dev; 3347398f382cSDaniel Borkmann else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) 3348c26a8016SLuiz Capitulino best = pkt_dev; 33491da177e4SLinus Torvalds } 33508788370aSJesper Dangaard Brouer rcu_read_unlock(); 33518788370aSJesper Dangaard Brouer 33521da177e4SLinus Torvalds return best; 33531da177e4SLinus Torvalds } 33541da177e4SLinus Torvalds 3355222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3356222f1806SLuiz Capitulino { 3357c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 33581da177e4SLinus Torvalds 3359f9467eaeSJoe Perches func_enter(); 33601da177e4SLinus Torvalds 33618788370aSJesper Dangaard Brouer rcu_read_lock(); 33621da177e4SLinus Torvalds 33638788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3364c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 336595ed63f7SArthur Kepner } 336695ed63f7SArthur Kepner 33678788370aSJesper Dangaard Brouer rcu_read_unlock(); 336895ed63f7SArthur Kepner } 336995ed63f7SArthur Kepner 337095ed63f7SArthur Kepner /* 337195ed63f7SArthur Kepner * one of our devices needs to be removed - find it 337295ed63f7SArthur Kepner * and remove it 337395ed63f7SArthur Kepner */ 337495ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 337595ed63f7SArthur Kepner { 3376c26a8016SLuiz Capitulino struct list_head *q, *n; 3377c26a8016SLuiz Capitulino struct pktgen_dev *cur; 337895ed63f7SArthur Kepner 3379f9467eaeSJoe Perches func_enter(); 338095ed63f7SArthur Kepner 3381c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3382c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 338395ed63f7SArthur Kepner 3384222f1806SLuiz Capitulino if (!cur->removal_mark) 3385222f1806SLuiz Capitulino continue; 338695ed63f7SArthur Kepner 338795ed63f7SArthur Kepner kfree_skb(cur->skb); 338895ed63f7SArthur Kepner cur->skb = NULL; 338995ed63f7SArthur Kepner 339095ed63f7SArthur Kepner pktgen_remove_device(t, cur); 339195ed63f7SArthur Kepner 339295ed63f7SArthur Kepner break; 339395ed63f7SArthur Kepner } 33941da177e4SLinus Torvalds } 33951da177e4SLinus Torvalds 33961da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 33971da177e4SLinus Torvalds { 3398c26a8016SLuiz Capitulino struct list_head *q, *n; 3399c26a8016SLuiz Capitulino struct pktgen_dev *cur; 34001da177e4SLinus Torvalds 3401f9467eaeSJoe Perches func_enter(); 3402f9467eaeSJoe Perches 34031da177e4SLinus Torvalds /* Remove all devices, free mem */ 34041da177e4SLinus Torvalds 3405c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3406c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 340795ed63f7SArthur Kepner 340895ed63f7SArthur Kepner kfree_skb(cur->skb); 340995ed63f7SArthur Kepner cur->skb = NULL; 341095ed63f7SArthur Kepner 34111da177e4SLinus Torvalds pktgen_remove_device(t, cur); 34121da177e4SLinus Torvalds } 34131da177e4SLinus Torvalds } 34141da177e4SLinus Torvalds 34151da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 34161da177e4SLinus Torvalds { 34171da177e4SLinus Torvalds /* Remove from the thread list */ 34184e58a027SCong Wang remove_proc_entry(t->tsk->comm, t->net->proc_dir); 34191da177e4SLinus Torvalds } 34201da177e4SLinus Torvalds 3421ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 34223791decbSStephen Hemminger { 3423398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 34243791decbSStephen Hemminger schedule(); 3425398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 34263791decbSStephen Hemminger } 34273791decbSStephen Hemminger 3428ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3429ef87979cSStephen Hemminger { 3430398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 3431ef87979cSStephen Hemminger 343263354797SReshetova, Elena while (refcount_read(&(pkt_dev->skb->users)) != 1) { 3433ef87979cSStephen Hemminger if (signal_pending(current)) 3434ef87979cSStephen Hemminger break; 3435ef87979cSStephen Hemminger 3436ef87979cSStephen Hemminger if (need_resched()) 3437ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3438ef87979cSStephen Hemminger else 3439ef87979cSStephen Hemminger cpu_relax(); 3440ef87979cSStephen Hemminger } 3441398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 3442ef87979cSStephen Hemminger } 3443fd29cf72SStephen Hemminger 3444475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 34451da177e4SLinus Torvalds { 34466aa7de05SMark Rutland unsigned int burst = READ_ONCE(pkt_dev->burst); 344700829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 3448fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 344962f64aedSAlexei Starovoitov struct sk_buff *skb; 34501da177e4SLinus Torvalds int ret; 34511da177e4SLinus Torvalds 3452ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3453ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 34541da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34553791decbSStephen Hemminger return; 34561da177e4SLinus Torvalds } 34571da177e4SLinus Torvalds 3458ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3459ef87979cSStephen Hemminger * "never transmit" 3460ef87979cSStephen Hemminger */ 3461ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3462398f382cSDaniel Borkmann pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX); 3463ef87979cSStephen Hemminger return; 3464ef87979cSStephen Hemminger } 3465ef87979cSStephen Hemminger 3466ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 34677d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 34687d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 34691da177e4SLinus Torvalds /* build a new pkt */ 34701da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 34711da177e4SLinus Torvalds 34721da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 34731da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3474f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 34751da177e4SLinus Torvalds schedule(); 34761da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 34773791decbSStephen Hemminger return; 34781da177e4SLinus Torvalds } 3479baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 34801da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 34811da177e4SLinus Torvalds } 34821da177e4SLinus Torvalds 3483ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3484ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3485ef87979cSStephen Hemminger 348662f64aedSAlexei Starovoitov if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) { 348762f64aedSAlexei Starovoitov skb = pkt_dev->skb; 348862f64aedSAlexei Starovoitov skb->protocol = eth_type_trans(skb, skb->dev); 348963354797SReshetova, Elena refcount_add(burst, &skb->users); 349062f64aedSAlexei Starovoitov local_bh_disable(); 349162f64aedSAlexei Starovoitov do { 349262f64aedSAlexei Starovoitov ret = netif_receive_skb(skb); 349362f64aedSAlexei Starovoitov if (ret == NET_RX_DROP) 349462f64aedSAlexei Starovoitov pkt_dev->errors++; 349562f64aedSAlexei Starovoitov pkt_dev->sofar++; 349662f64aedSAlexei Starovoitov pkt_dev->seq_num++; 349763354797SReshetova, Elena if (refcount_read(&skb->users) != burst) { 349862f64aedSAlexei Starovoitov /* skb was queued by rps/rfs or taps, 349962f64aedSAlexei Starovoitov * so cannot reuse this skb 350062f64aedSAlexei Starovoitov */ 350163354797SReshetova, Elena WARN_ON(refcount_sub_and_test(burst - 1, &skb->users)); 350262f64aedSAlexei Starovoitov /* get out of the loop and wait 350362f64aedSAlexei Starovoitov * until skb is consumed 350462f64aedSAlexei Starovoitov */ 350562f64aedSAlexei Starovoitov break; 350662f64aedSAlexei Starovoitov } 350762f64aedSAlexei Starovoitov /* skb was 'freed' by stack, so clean few 350862f64aedSAlexei Starovoitov * bits and reuse it 350962f64aedSAlexei Starovoitov */ 35102c64605bSPablo Neira Ayuso skb_reset_redirect(skb); 351162f64aedSAlexei Starovoitov } while (--burst > 0); 351262f64aedSAlexei Starovoitov goto out; /* Skips xmit_mode M_START_XMIT */ 35130967f244SJohn Fastabend } else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) { 35140967f244SJohn Fastabend local_bh_disable(); 351563354797SReshetova, Elena refcount_inc(&pkt_dev->skb->users); 35160967f244SJohn Fastabend 35170967f244SJohn Fastabend ret = dev_queue_xmit(pkt_dev->skb); 35180967f244SJohn Fastabend switch (ret) { 35190967f244SJohn Fastabend case NET_XMIT_SUCCESS: 35200967f244SJohn Fastabend pkt_dev->sofar++; 35210967f244SJohn Fastabend pkt_dev->seq_num++; 35220967f244SJohn Fastabend pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 35230967f244SJohn Fastabend break; 35240967f244SJohn Fastabend case NET_XMIT_DROP: 35250967f244SJohn Fastabend case NET_XMIT_CN: 35260967f244SJohn Fastabend /* These are all valid return codes for a qdisc but 35270967f244SJohn Fastabend * indicate packets are being dropped or will likely 35280967f244SJohn Fastabend * be dropped soon. 35290967f244SJohn Fastabend */ 35300967f244SJohn Fastabend case NETDEV_TX_BUSY: 35310967f244SJohn Fastabend /* qdisc may call dev_hard_start_xmit directly in cases 35320967f244SJohn Fastabend * where no queues exist e.g. loopback device, virtual 35330967f244SJohn Fastabend * devices, etc. In this case we need to handle 35340967f244SJohn Fastabend * NETDEV_TX_ codes. 35350967f244SJohn Fastabend */ 35360967f244SJohn Fastabend default: 35370967f244SJohn Fastabend pkt_dev->errors++; 35380967f244SJohn Fastabend net_info_ratelimited("%s xmit error: %d\n", 35390967f244SJohn Fastabend pkt_dev->odevname, ret); 35400967f244SJohn Fastabend break; 35410967f244SJohn Fastabend } 35420967f244SJohn Fastabend goto out; 354362f64aedSAlexei Starovoitov } 354462f64aedSAlexei Starovoitov 354510c51b56SDaniel Borkmann txq = skb_get_tx_queue(odev, pkt_dev->skb); 3546fd2ea0a7SDavid S. Miller 35470f2eea4bSDaniel Borkmann local_bh_disable(); 35480f2eea4bSDaniel Borkmann 35490f2eea4bSDaniel Borkmann HARD_TX_LOCK(odev, txq, smp_processor_id()); 35505b8db2f5SStephen Hemminger 35516f25cd47SDaniel Borkmann if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) { 35520835acfeSEric Dumazet pkt_dev->last_ok = 0; 35530835acfeSEric Dumazet goto unlock; 35540835acfeSEric Dumazet } 355563354797SReshetova, Elena refcount_add(burst, &pkt_dev->skb->users); 355638b2cf29SAlexei Starovoitov 355738b2cf29SAlexei Starovoitov xmit_more: 355838b2cf29SAlexei Starovoitov ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); 3559ef87979cSStephen Hemminger 35605b8db2f5SStephen Hemminger switch (ret) { 35615b8db2f5SStephen Hemminger case NETDEV_TX_OK: 35621da177e4SLinus Torvalds pkt_dev->last_ok = 1; 35631da177e4SLinus Torvalds pkt_dev->sofar++; 35641da177e4SLinus Torvalds pkt_dev->seq_num++; 3565baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 356638b2cf29SAlexei Starovoitov if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq)) 356738b2cf29SAlexei Starovoitov goto xmit_more; 35685b8db2f5SStephen Hemminger break; 3569f466dba1SJohn Fastabend case NET_XMIT_DROP: 3570f466dba1SJohn Fastabend case NET_XMIT_CN: 3571f466dba1SJohn Fastabend /* skb has been consumed */ 3572f466dba1SJohn Fastabend pkt_dev->errors++; 3573f466dba1SJohn Fastabend break; 35745b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 3575e87cc472SJoe Perches net_info_ratelimited("%s xmit error: %d\n", 3576e87cc472SJoe Perches pkt_dev->odevname, ret); 35771da177e4SLinus Torvalds pkt_dev->errors++; 3578df561f66SGustavo A. R. Silva fallthrough; 35795b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 35805b8db2f5SStephen Hemminger /* Retry it next time */ 358163354797SReshetova, Elena refcount_dec(&(pkt_dev->skb->users)); 35821da177e4SLinus Torvalds pkt_dev->last_ok = 0; 35831da177e4SLinus Torvalds } 358438b2cf29SAlexei Starovoitov if (unlikely(burst)) 358563354797SReshetova, Elena WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users)); 35860835acfeSEric Dumazet unlock: 35870f2eea4bSDaniel Borkmann HARD_TX_UNLOCK(odev, txq); 35880f2eea4bSDaniel Borkmann 358962f64aedSAlexei Starovoitov out: 35900f2eea4bSDaniel Borkmann local_bh_enable(); 35911da177e4SLinus Torvalds 35921da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 35931da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3594ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 35951da177e4SLinus Torvalds 35961da177e4SLinus Torvalds /* Done with this */ 35971da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 35981da177e4SLinus Torvalds } 35991da177e4SLinus Torvalds } 36001da177e4SLinus Torvalds 36011da177e4SLinus Torvalds /* 36021da177e4SLinus Torvalds * Main loop of the thread goes here 36031da177e4SLinus Torvalds */ 36041da177e4SLinus Torvalds 3605ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 36061da177e4SLinus Torvalds { 3607ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 36081da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 36091da177e4SLinus Torvalds int cpu = t->cpu; 36101da177e4SLinus Torvalds 3611275b1e88SDi Zhu WARN_ON(smp_processor_id() != cpu); 36121da177e4SLinus Torvalds 36131da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3614d3ede327SDenis V. Lunev complete(&t->start_done); 36151da177e4SLinus Torvalds 3616f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 36171da177e4SLinus Torvalds 361883144186SRafael J. Wysocki set_freezable(); 361983144186SRafael J. Wysocki 3620ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3621ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3622ee74baa7SDavid S. Miller 3623ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 36244e58a027SCong Wang if (t->net->pktgen_exiting) 3625551eaff1SEric Dumazet break; 3626ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3627ef87979cSStephen Hemminger t->control != 0, 3628ef87979cSStephen Hemminger HZ/10); 36291b3f720bSRafael J. Wysocki try_to_freeze(); 3630ef87979cSStephen Hemminger continue; 3631ee74baa7SDavid S. Miller } 36321da177e4SLinus Torvalds 3633ef87979cSStephen Hemminger if (likely(pkt_dev)) { 36341da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 36351da177e4SLinus Torvalds 3636ef87979cSStephen Hemminger if (need_resched()) 3637ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3638ef87979cSStephen Hemminger else 3639ef87979cSStephen Hemminger cpu_relax(); 3640ef87979cSStephen Hemminger } 3641ef87979cSStephen Hemminger 36421da177e4SLinus Torvalds if (t->control & T_STOP) { 36431da177e4SLinus Torvalds pktgen_stop(t); 36441da177e4SLinus Torvalds t->control &= ~(T_STOP); 36451da177e4SLinus Torvalds } 36461da177e4SLinus Torvalds 36471da177e4SLinus Torvalds if (t->control & T_RUN) { 36481da177e4SLinus Torvalds pktgen_run(t); 36491da177e4SLinus Torvalds t->control &= ~(T_RUN); 36501da177e4SLinus Torvalds } 36511da177e4SLinus Torvalds 365295ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 36531da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 365495ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 365595ed63f7SArthur Kepner } 365695ed63f7SArthur Kepner 365795ed63f7SArthur Kepner if (t->control & T_REMDEV) { 365895ed63f7SArthur Kepner pktgen_rem_one_if(t); 36591da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 36601da177e4SLinus Torvalds } 36611da177e4SLinus Torvalds 366209fe3ef4SAndrew Morton try_to_freeze(); 36631da177e4SLinus Torvalds } 36641da177e4SLinus Torvalds 3665f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 36661da177e4SLinus Torvalds pktgen_stop(t); 36671da177e4SLinus Torvalds 3668f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 36691da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 36701da177e4SLinus Torvalds 3671f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 36721da177e4SLinus Torvalds pktgen_rem_thread(t); 3673cdcdbe0bSLuiz Capitulino 3674ee74baa7SDavid S. Miller return 0; 36751da177e4SLinus Torvalds } 36761da177e4SLinus Torvalds 3677222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 36783e984840SEric Dumazet const char *ifname, bool exact) 36791da177e4SLinus Torvalds { 3680c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 36813e984840SEric Dumazet size_t len = strlen(ifname); 36821da177e4SLinus Torvalds 36838788370aSJesper Dangaard Brouer rcu_read_lock(); 36848788370aSJesper Dangaard Brouer list_for_each_entry_rcu(p, &t->if_list, list) 36853e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 36863e984840SEric Dumazet if (p->odevname[len]) { 36873e984840SEric Dumazet if (exact || p->odevname[len] != '@') 36883e984840SEric Dumazet continue; 36893e984840SEric Dumazet } 3690c26a8016SLuiz Capitulino pkt_dev = p; 36911da177e4SLinus Torvalds break; 36921da177e4SLinus Torvalds } 36931da177e4SLinus Torvalds 36948788370aSJesper Dangaard Brouer rcu_read_unlock(); 3695f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 36961da177e4SLinus Torvalds return pkt_dev; 36971da177e4SLinus Torvalds } 36981da177e4SLinus Torvalds 36991da177e4SLinus Torvalds /* 37001da177e4SLinus Torvalds * Adds a dev at front of if_list. 37011da177e4SLinus Torvalds */ 37021da177e4SLinus Torvalds 3703222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3704222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 37051da177e4SLinus Torvalds { 37061da177e4SLinus Torvalds int rv = 0; 37071da177e4SLinus Torvalds 37088788370aSJesper Dangaard Brouer /* This function cannot be called concurrently, as its called 37098788370aSJesper Dangaard Brouer * under pktgen_thread_lock mutex, but it can run from 37108788370aSJesper Dangaard Brouer * userspace on another CPU than the kthread. The if_lock() 37118788370aSJesper Dangaard Brouer * is used here to sync with concurrent instances of 37128788370aSJesper Dangaard Brouer * _rem_dev_from_if_list() invoked via kthread, which is also 37138788370aSJesper Dangaard Brouer * updating the if_list */ 37141da177e4SLinus Torvalds if_lock(t); 37151da177e4SLinus Torvalds 37161da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3717f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 37181da177e4SLinus Torvalds rv = -EBUSY; 37191da177e4SLinus Torvalds goto out; 37201da177e4SLinus Torvalds } 3721c26a8016SLuiz Capitulino 37221da177e4SLinus Torvalds pkt_dev->running = 0; 37238788370aSJesper Dangaard Brouer pkt_dev->pg_thread = t; 37248788370aSJesper Dangaard Brouer list_add_rcu(&pkt_dev->list, &t->if_list); 37251da177e4SLinus Torvalds 37261da177e4SLinus Torvalds out: 37271da177e4SLinus Torvalds if_unlock(t); 37281da177e4SLinus Torvalds return rv; 37291da177e4SLinus Torvalds } 37301da177e4SLinus Torvalds 37311da177e4SLinus Torvalds /* Called under thread lock */ 37321da177e4SLinus Torvalds 37331da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 37341da177e4SLinus Torvalds { 37351da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 373639df232fSStephen Hemminger int err; 37373291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 37381da177e4SLinus Torvalds 37391da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 37401da177e4SLinus Torvalds 37414e58a027SCong Wang pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND); 3742d50a6b56SStephen Hemminger if (pkt_dev) { 3743f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3744d50a6b56SStephen Hemminger return -EBUSY; 3745d50a6b56SStephen Hemminger } 37461da177e4SLinus Torvalds 37473291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 37481da177e4SLinus Torvalds if (!pkt_dev) 37491da177e4SLinus Torvalds return -ENOMEM; 37501da177e4SLinus Torvalds 3751593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 3752fd7becedSKees Cook pkt_dev->flows = vzalloc_node(array_size(MAX_CFLOWS, 3753fd7becedSKees Cook sizeof(struct flow_state)), 37543291b9dbSEric Dumazet node); 37551da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 37561da177e4SLinus Torvalds kfree(pkt_dev); 37571da177e4SLinus Torvalds return -ENOMEM; 37581da177e4SLinus Torvalds } 37591da177e4SLinus Torvalds 376095ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 37611da177e4SLinus Torvalds pkt_dev->nfrags = 0; 3762fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 37631da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 37641da177e4SLinus Torvalds pkt_dev->sofar = 0; 37651da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 37661da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 37671da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 37681da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 376934954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 377034954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 377134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 377234954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 377334954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 377434954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 377538b2cf29SAlexei Starovoitov pkt_dev->burst = 1; 377698fa15f3SAnshuman Khandual pkt_dev->node = NUMA_NO_NODE; 377734954ddcSFrancesco Fondelli 37784e58a027SCong Wang err = pktgen_setup_dev(t->net, pkt_dev, ifname); 377939df232fSStephen Hemminger if (err) 378039df232fSStephen Hemminger goto out1; 3781d8873315SNeil Horman if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) 3782d8873315SNeil Horman pkt_dev->clone_skb = pg_clone_skb_d; 37831da177e4SLinus Torvalds 37844e58a027SCong Wang pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir, 378597a32539SAlexey Dobriyan &pktgen_if_proc_ops, pkt_dev); 378639df232fSStephen Hemminger if (!pkt_dev->entry) { 3787f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3788d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 378939df232fSStephen Hemminger err = -EINVAL; 379039df232fSStephen Hemminger goto out2; 379139df232fSStephen Hemminger } 3792a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3793a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3794a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3795cf93d47eSFan Du 3796cf93d47eSFan Du /* xfrm tunnel mode needs additional dst to extract outter 3797cf93d47eSFan Du * ip header protocol/ttl/id field, here creat a phony one. 3798cf93d47eSFan Du * instead of looking for a valid rt, which definitely hurting 3799cf93d47eSFan Du * performance under such circumstance. 3800cf93d47eSFan Du */ 3801cf93d47eSFan Du pkt_dev->dstops.family = AF_INET; 3802b6ca8bd5SDavid Miller pkt_dev->xdst.u.dst.dev = pkt_dev->odev; 3803b6ca8bd5SDavid Miller dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false); 3804b6ca8bd5SDavid Miller pkt_dev->xdst.child = &pkt_dev->xdst.u.dst; 3805b6ca8bd5SDavid Miller pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops; 3806a553e4a6SJamal Hadi Salim #endif 380739df232fSStephen Hemminger 380839df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 380939df232fSStephen Hemminger out2: 3810035f1f2bSEric Dumazet dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); 381139df232fSStephen Hemminger out1: 3812a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3813a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3814a553e4a6SJamal Hadi Salim #endif 38151da177e4SLinus Torvalds vfree(pkt_dev->flows); 38161da177e4SLinus Torvalds kfree(pkt_dev); 381739df232fSStephen Hemminger return err; 38181da177e4SLinus Torvalds } 38191da177e4SLinus Torvalds 38204e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) 38211da177e4SLinus Torvalds { 3822cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3823d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3824ee74baa7SDavid S. Miller struct task_struct *p; 38251da177e4SLinus Torvalds 38263291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 38273291b9dbSEric Dumazet cpu_to_node(cpu)); 38281da177e4SLinus Torvalds if (!t) { 3829f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 38301da177e4SLinus Torvalds return -ENOMEM; 38311da177e4SLinus Torvalds } 38321da177e4SLinus Torvalds 38339a0b1e8bSEric Dumazet mutex_init(&t->if_lock); 38341da177e4SLinus Torvalds t->cpu = cpu; 38351da177e4SLinus Torvalds 3836ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3837ee74baa7SDavid S. Miller 38384e58a027SCong Wang list_add_tail(&t->th_list, &pn->pktgen_threads); 3839d3ede327SDenis V. Lunev init_completion(&t->start_done); 3840ee74baa7SDavid S. Miller 384194dcf29aSEric Dumazet p = kthread_create_on_node(pktgen_thread_worker, 384294dcf29aSEric Dumazet t, 384394dcf29aSEric Dumazet cpu_to_node(cpu), 384494dcf29aSEric Dumazet "kpktgend_%d", cpu); 3845ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3846355db391SLeesoo Ahn pr_err("kthread_create_on_node() failed for cpu %d\n", t->cpu); 3847ee74baa7SDavid S. Miller list_del(&t->th_list); 3848ee74baa7SDavid S. Miller kfree(t); 3849ee74baa7SDavid S. Miller return PTR_ERR(p); 3850ee74baa7SDavid S. Miller } 3851ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3852ee74baa7SDavid S. Miller t->tsk = p; 3853ee74baa7SDavid S. Miller 38544e58a027SCong Wang pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir, 385597a32539SAlexey Dobriyan &pktgen_thread_proc_ops, t); 3856d50a6b56SStephen Hemminger if (!pe) { 3857f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3858ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3859ee74baa7SDavid S. Miller kthread_stop(p); 3860ee74baa7SDavid S. Miller list_del(&t->th_list); 38611da177e4SLinus Torvalds kfree(t); 38621da177e4SLinus Torvalds return -EINVAL; 38631da177e4SLinus Torvalds } 3864d50a6b56SStephen Hemminger 38654e58a027SCong Wang t->net = pn; 38661fbe4b46SOleg Nesterov get_task_struct(p); 3867ee74baa7SDavid S. Miller wake_up_process(p); 3868d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 38691da177e4SLinus Torvalds 38701da177e4SLinus Torvalds return 0; 38711da177e4SLinus Torvalds } 38721da177e4SLinus Torvalds 38731da177e4SLinus Torvalds /* 38741da177e4SLinus Torvalds * Removes a device from the thread if_list. 38751da177e4SLinus Torvalds */ 3876222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3877222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38781da177e4SLinus Torvalds { 3879c26a8016SLuiz Capitulino struct list_head *q, *n; 3880c26a8016SLuiz Capitulino struct pktgen_dev *p; 38811da177e4SLinus Torvalds 38828788370aSJesper Dangaard Brouer if_lock(t); 3883c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3884c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3885c26a8016SLuiz Capitulino if (p == pkt_dev) 38868788370aSJesper Dangaard Brouer list_del_rcu(&p->list); 38871da177e4SLinus Torvalds } 38888788370aSJesper Dangaard Brouer if_unlock(t); 38891da177e4SLinus Torvalds } 38901da177e4SLinus Torvalds 3891222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3892222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38931da177e4SLinus Torvalds { 3894f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 38951da177e4SLinus Torvalds 38961da177e4SLinus Torvalds if (pkt_dev->running) { 3897294a0b7fSJoe Perches pr_warn("WARNING: trying to remove a running interface, stopping it now\n"); 38981da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 38991da177e4SLinus Torvalds } 39001da177e4SLinus Torvalds 39011da177e4SLinus Torvalds /* Dis-associate from the interface */ 39021da177e4SLinus Torvalds 39031da177e4SLinus Torvalds if (pkt_dev->odev) { 3904035f1f2bSEric Dumazet dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); 39051da177e4SLinus Torvalds pkt_dev->odev = NULL; 39061da177e4SLinus Torvalds } 39071da177e4SLinus Torvalds 39088788370aSJesper Dangaard Brouer /* Remove proc before if_list entry, because add_device uses 39098788370aSJesper Dangaard Brouer * list to determine if interface already exist, avoid race 39108788370aSJesper Dangaard Brouer * with proc_create_data() */ 3911a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 39121da177e4SLinus Torvalds 39138788370aSJesper Dangaard Brouer /* And update the thread if_list */ 39148788370aSJesper Dangaard Brouer _rem_dev_from_if_list(t, pkt_dev); 39158788370aSJesper Dangaard Brouer 3916a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3917a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3918a553e4a6SJamal Hadi Salim #endif 39191da177e4SLinus Torvalds vfree(pkt_dev->flows); 392026ad7879SEric Dumazet if (pkt_dev->page) 392126ad7879SEric Dumazet put_page(pkt_dev->page); 39228788370aSJesper Dangaard Brouer kfree_rcu(pkt_dev, rcu); 39231da177e4SLinus Torvalds return 0; 39241da177e4SLinus Torvalds } 39251da177e4SLinus Torvalds 39264e58a027SCong Wang static int __net_init pg_net_init(struct net *net) 39271da177e4SLinus Torvalds { 39284e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3929d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 39304e58a027SCong Wang int cpu, ret = 0; 3931d50a6b56SStephen Hemminger 39324e58a027SCong Wang pn->net = net; 39334e58a027SCong Wang INIT_LIST_HEAD(&pn->pktgen_threads); 39344e58a027SCong Wang pn->pktgen_exiting = false; 39354e58a027SCong Wang pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net); 39364e58a027SCong Wang if (!pn->proc_dir) { 39374e58a027SCong Wang pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); 3938d50a6b56SStephen Hemminger return -ENODEV; 39391da177e4SLinus Torvalds } 394097a32539SAlexey Dobriyan pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_proc_ops); 39414e58a027SCong Wang if (pe == NULL) { 39424e58a027SCong Wang pr_err("cannot create %s procfs entry\n", PGCTRL); 39434e58a027SCong Wang ret = -EINVAL; 39444e58a027SCong Wang goto remove; 39454e58a027SCong Wang } 39461da177e4SLinus Torvalds 3947670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 39488024bb24SLuiz Capitulino int err; 39491da177e4SLinus Torvalds 39504e58a027SCong Wang err = pktgen_create_thread(cpu, pn); 39518024bb24SLuiz Capitulino if (err) 39524e58a027SCong Wang pr_warn("Cannot create thread for cpu %d (%d)\n", 3953f9467eaeSJoe Perches cpu, err); 39541da177e4SLinus Torvalds } 39558024bb24SLuiz Capitulino 39564e58a027SCong Wang if (list_empty(&pn->pktgen_threads)) { 39574e58a027SCong Wang pr_err("Initialization failed for all threads\n"); 3958ce14f894SWANG Cong ret = -ENODEV; 39594e58a027SCong Wang goto remove_entry; 39608024bb24SLuiz Capitulino } 39618024bb24SLuiz Capitulino 39621da177e4SLinus Torvalds return 0; 3963ce14f894SWANG Cong 39644e58a027SCong Wang remove_entry: 39654e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 39664e58a027SCong Wang remove: 3967ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 3968ce14f894SWANG Cong return ret; 39691da177e4SLinus Torvalds } 39701da177e4SLinus Torvalds 39714e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net) 39721da177e4SLinus Torvalds { 39734e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3974cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3975cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 3976d4b11335SEric Dumazet LIST_HEAD(list); 39771da177e4SLinus Torvalds 39781da177e4SLinus Torvalds /* Stop all interfaces & threads */ 39794e58a027SCong Wang pn->pktgen_exiting = true; 39801da177e4SLinus Torvalds 3981c57b5468SEric Dumazet mutex_lock(&pktgen_thread_lock); 39824e58a027SCong Wang list_splice_init(&pn->pktgen_threads, &list); 3983c57b5468SEric Dumazet mutex_unlock(&pktgen_thread_lock); 3984c57b5468SEric Dumazet 3985c57b5468SEric Dumazet list_for_each_safe(q, n, &list) { 3986cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3987c57b5468SEric Dumazet list_del(&t->th_list); 3988ee74baa7SDavid S. Miller kthread_stop(t->tsk); 39891fbe4b46SOleg Nesterov put_task_struct(t->tsk); 3990ee74baa7SDavid S. Miller kfree(t); 39911da177e4SLinus Torvalds } 39921da177e4SLinus Torvalds 39934e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 3994ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 39954e58a027SCong Wang } 39961da177e4SLinus Torvalds 39974e58a027SCong Wang static struct pernet_operations pg_net_ops = { 39984e58a027SCong Wang .init = pg_net_init, 39994e58a027SCong Wang .exit = pg_net_exit, 40004e58a027SCong Wang .id = &pg_net_id, 40014e58a027SCong Wang .size = sizeof(struct pktgen_net), 40024e58a027SCong Wang }; 40034e58a027SCong Wang 40044e58a027SCong Wang static int __init pg_init(void) 40054e58a027SCong Wang { 40064e58a027SCong Wang int ret = 0; 40074e58a027SCong Wang 40084e58a027SCong Wang pr_info("%s", version); 40094e58a027SCong Wang ret = register_pernet_subsys(&pg_net_ops); 40104e58a027SCong Wang if (ret) 40114e58a027SCong Wang return ret; 40124e58a027SCong Wang ret = register_netdevice_notifier(&pktgen_notifier_block); 40134e58a027SCong Wang if (ret) 40144e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 40154e58a027SCong Wang 40164e58a027SCong Wang return ret; 40174e58a027SCong Wang } 40184e58a027SCong Wang 40194e58a027SCong Wang static void __exit pg_cleanup(void) 40204e58a027SCong Wang { 40214e58a027SCong Wang unregister_netdevice_notifier(&pktgen_notifier_block); 40224e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 40238788370aSJesper Dangaard Brouer /* Don't need rcu_barrier() due to use of kfree_rcu() */ 40241da177e4SLinus Torvalds } 40251da177e4SLinus Torvalds 40261da177e4SLinus Torvalds module_init(pg_init); 40271da177e4SLinus Torvalds module_exit(pg_cleanup); 40281da177e4SLinus Torvalds 4029c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 40301da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 40311da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4032c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 40331da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 4034c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 40351da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 4036c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 40371da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 4038c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 40391da177e4SLinus Torvalds module_param(debug, int, 0); 4040c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 4041