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) 1781da177e4SLinus Torvalds 179f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__); 180f9467eaeSJoe Perches 1816f107c74SDmitry Safonov #define PKT_FLAGS \ 1826f107c74SDmitry Safonov pf(IPV6) /* Interface in IPV6 Mode */ \ 1836f107c74SDmitry Safonov pf(IPSRC_RND) /* IP-Src Random */ \ 1846f107c74SDmitry Safonov pf(IPDST_RND) /* IP-Dst Random */ \ 1856f107c74SDmitry Safonov pf(TXSIZE_RND) /* Transmit size is random */ \ 1866f107c74SDmitry Safonov pf(UDPSRC_RND) /* UDP-Src Random */ \ 1876f107c74SDmitry Safonov pf(UDPDST_RND) /* UDP-Dst Random */ \ 1886f107c74SDmitry Safonov pf(UDPCSUM) /* Include UDP checksum */ \ 1896f107c74SDmitry Safonov pf(NO_TIMESTAMP) /* Don't timestamp packets (default TS) */ \ 1906f107c74SDmitry Safonov pf(MPLS_RND) /* Random MPLS labels */ \ 1916f107c74SDmitry Safonov pf(QUEUE_MAP_RND) /* queue map Random */ \ 1926f107c74SDmitry Safonov pf(QUEUE_MAP_CPU) /* queue map mirrors smp_processor_id() */ \ 1936f107c74SDmitry Safonov pf(FLOW_SEQ) /* Sequential flows */ \ 1946f107c74SDmitry Safonov pf(IPSEC) /* ipsec on for flows */ \ 1956f107c74SDmitry Safonov pf(MACSRC_RND) /* MAC-Src Random */ \ 1966f107c74SDmitry Safonov pf(MACDST_RND) /* MAC-Dst Random */ \ 1976f107c74SDmitry Safonov pf(VID_RND) /* Random VLAN ID */ \ 1986f107c74SDmitry Safonov pf(SVID_RND) /* Random SVLAN ID */ \ 1996f107c74SDmitry Safonov pf(NODE) /* Node memory alloc*/ \ 2006f107c74SDmitry Safonov 2016f107c74SDmitry Safonov #define pf(flag) flag##_SHIFT, 2026f107c74SDmitry Safonov enum pkt_flags { 2036f107c74SDmitry Safonov PKT_FLAGS 2046f107c74SDmitry Safonov }; 2056f107c74SDmitry Safonov #undef pf 2066f107c74SDmitry Safonov 2071da177e4SLinus Torvalds /* Device flag bits */ 2086f107c74SDmitry Safonov #define pf(flag) static const __u32 F_##flag = (1<<flag##_SHIFT); 2096f107c74SDmitry Safonov PKT_FLAGS 2106f107c74SDmitry Safonov #undef pf 2111da177e4SLinus Torvalds 21299c6d3d2SDmitry Safonov #define pf(flag) __stringify(flag), 21399c6d3d2SDmitry Safonov static char *pkt_flag_names[] = { 21499c6d3d2SDmitry Safonov PKT_FLAGS 21599c6d3d2SDmitry Safonov }; 21699c6d3d2SDmitry Safonov #undef pf 21799c6d3d2SDmitry Safonov 21899c6d3d2SDmitry Safonov #define NR_PKT_FLAGS ARRAY_SIZE(pkt_flag_names) 21999c6d3d2SDmitry Safonov 2201da177e4SLinus Torvalds /* Thread control flag bits */ 2216b80d6a6SStephen Hemminger #define T_STOP (1<<0) /* Stop run */ 2226b80d6a6SStephen Hemminger #define T_RUN (1<<1) /* Start run */ 2236b80d6a6SStephen Hemminger #define T_REMDEVALL (1<<2) /* Remove all devs */ 2246b80d6a6SStephen Hemminger #define T_REMDEV (1<<3) /* Remove one dev */ 2251da177e4SLinus Torvalds 22662f64aedSAlexei Starovoitov /* Xmit modes */ 22762f64aedSAlexei Starovoitov #define M_START_XMIT 0 /* Default normal TX */ 22862f64aedSAlexei Starovoitov #define M_NETIF_RECEIVE 1 /* Inject packets into stack */ 2290967f244SJohn Fastabend #define M_QUEUE_XMIT 2 /* Inject packet into qdisc */ 23062f64aedSAlexei Starovoitov 2318788370aSJesper Dangaard Brouer /* If lock -- protects updating of if_list */ 2329a0b1e8bSEric Dumazet #define if_lock(t) mutex_lock(&(t->if_lock)); 2339a0b1e8bSEric Dumazet #define if_unlock(t) mutex_unlock(&(t->if_lock)); 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 2361da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 237d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen" 238d50a6b56SStephen Hemminger #define PGCTRL "pgctrl" 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds #define MAX_CFLOWS 65536 2411da177e4SLinus Torvalds 24234954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 24334954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 24434954ddcSFrancesco Fondelli 245222f1806SLuiz Capitulino struct flow_state { 246252e3346SAl Viro __be32 cur_daddr; 2471da177e4SLinus Torvalds int count; 248a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 249a553e4a6SJamal Hadi Salim struct xfrm_state *x; 250a553e4a6SJamal Hadi Salim #endif 251007a531bSJamal Hadi Salim __u32 flags; 2521da177e4SLinus Torvalds }; 2531da177e4SLinus Torvalds 254007a531bSJamal Hadi Salim /* flow flag bits */ 255007a531bSJamal Hadi Salim #define F_INIT (1<<0) /* flow has been initialized */ 256007a531bSJamal Hadi Salim 2571da177e4SLinus Torvalds struct pktgen_dev { 2581da177e4SLinus Torvalds /* 2591da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 2601da177e4SLinus Torvalds */ 26139df232fSStephen Hemminger struct proc_dir_entry *entry; /* proc file */ 2621da177e4SLinus Torvalds struct pktgen_thread *pg_thread;/* the owner */ 26363adc6fbSStephen Hemminger struct list_head list; /* chaining in the thread's run-queue */ 2648788370aSJesper Dangaard Brouer struct rcu_head rcu; /* freed by RCU */ 2651da177e4SLinus Torvalds 26663adc6fbSStephen Hemminger int running; /* if false, the test will stop */ 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 2691da177e4SLinus Torvalds * we will do a random selection from within the range. 2701da177e4SLinus Torvalds */ 2711da177e4SLinus Torvalds __u32 flags; 27262f64aedSAlexei Starovoitov int xmit_mode; 27368bf9f0bSAmerigo Wang int min_pkt_size; 27468bf9f0bSAmerigo Wang int max_pkt_size; 27516dab72fSJamal Hadi Salim int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2761da177e4SLinus Torvalds int nfrags; 27762f64aedSAlexei Starovoitov int removal_mark; /* non-zero => the device is marked for 27862f64aedSAlexei Starovoitov * removal by worker thread */ 27962f64aedSAlexei Starovoitov 28026ad7879SEric Dumazet struct page *page; 281fd29cf72SStephen Hemminger u64 delay; /* nano-seconds */ 282fd29cf72SStephen Hemminger 2831da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 2841da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 2851da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 286f466dba1SJohn Fastabend __u64 errors; /* Errors when trying to transmit, */ 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds __u32 clone_count; 2911da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 29263adc6fbSStephen Hemminger * Or a failed transmit of some sort? 29363adc6fbSStephen Hemminger * This will keep sequence numbers in order 2941da177e4SLinus Torvalds */ 295fd29cf72SStephen Hemminger ktime_t next_tx; 296fd29cf72SStephen Hemminger ktime_t started_at; 297fd29cf72SStephen Hemminger ktime_t stopped_at; 298fd29cf72SStephen Hemminger u64 idle_acc; /* nano-seconds */ 299fd29cf72SStephen Hemminger 3001da177e4SLinus Torvalds __u32 seq_num; 3011da177e4SLinus Torvalds 30263adc6fbSStephen Hemminger int clone_skb; /* 30363adc6fbSStephen Hemminger * Use multiple SKBs during packet gen. 30463adc6fbSStephen Hemminger * If this number is greater than 1, then 30563adc6fbSStephen Hemminger * that many copies of the same packet will be 30663adc6fbSStephen Hemminger * sent before a new packet is allocated. 30763adc6fbSStephen Hemminger * If you want to send 1024 identical packets 30863adc6fbSStephen Hemminger * before creating a new packet, 30963adc6fbSStephen Hemminger * set clone_skb to 1024. 3101da177e4SLinus Torvalds */ 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3131da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3141da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3151da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds struct in6_addr in6_saddr; 3181da177e4SLinus Torvalds struct in6_addr in6_daddr; 3191da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 3201da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 3211da177e4SLinus Torvalds /* For ranges */ 3221da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 3231da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 3241da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 3251da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 3281da177e4SLinus Torvalds * defines the min/max for those ranges. 3291da177e4SLinus Torvalds */ 330252e3346SAl Viro __be32 saddr_min; /* inclusive, source IP address */ 331252e3346SAl Viro __be32 saddr_max; /* exclusive, source IP address */ 332252e3346SAl Viro __be32 daddr_min; /* inclusive, dest IP address */ 333252e3346SAl Viro __be32 daddr_max; /* exclusive, dest IP address */ 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 3361da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 3371da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 3381da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 3391da177e4SLinus Torvalds 3401ca7768cSFrancesco Fondelli /* DSCP + ECN */ 34163adc6fbSStephen Hemminger __u8 tos; /* six MSB of (former) IPv4 TOS 34263adc6fbSStephen Hemminger are for dscp codepoint */ 34363adc6fbSStephen Hemminger __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 34463adc6fbSStephen Hemminger (see RFC 3260, sec. 4) */ 3451ca7768cSFrancesco Fondelli 346ca6549afSSteven Whitehouse /* MPLS */ 34795c96174SEric Dumazet unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */ 348ca6549afSSteven Whitehouse __be32 labels[MAX_MPLS_LABELS]; 349ca6549afSSteven Whitehouse 35034954ddcSFrancesco Fondelli /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 35134954ddcSFrancesco Fondelli __u8 vlan_p; 35234954ddcSFrancesco Fondelli __u8 vlan_cfi; 35334954ddcSFrancesco Fondelli __u16 vlan_id; /* 0xffff means no vlan tag */ 35434954ddcSFrancesco Fondelli 35534954ddcSFrancesco Fondelli __u8 svlan_p; 35634954ddcSFrancesco Fondelli __u8 svlan_cfi; 35734954ddcSFrancesco Fondelli __u16 svlan_id; /* 0xffff means no svlan tag */ 35834954ddcSFrancesco Fondelli 3591da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 3601da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 3611da177e4SLinus Torvalds 362f404e9a6SKris Katterjohn unsigned char dst_mac[ETH_ALEN]; 363f404e9a6SKris Katterjohn unsigned char src_mac[ETH_ALEN]; 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 3661da177e4SLinus Torvalds __u32 cur_src_mac_offset; 367252e3346SAl Viro __be32 cur_saddr; 368252e3346SAl Viro __be32 cur_daddr; 36966ed1e5eSEric Dumazet __u16 ip_id; 3701da177e4SLinus Torvalds __u16 cur_udp_dst; 3711da177e4SLinus Torvalds __u16 cur_udp_src; 37245b270f8SRobert Olsson __u16 cur_queue_map; 3731da177e4SLinus Torvalds __u32 cur_pkt_size; 374baac8564SEric Dumazet __u32 last_pkt_size; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds __u8 hh[14]; 3771da177e4SLinus Torvalds /* = { 3781da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds We fill in SRC address later 3811da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3821da177e4SLinus Torvalds 0x08, 0x00 3831da177e4SLinus Torvalds }; 3841da177e4SLinus Torvalds */ 3851da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 3861da177e4SLinus Torvalds 38763adc6fbSStephen Hemminger struct sk_buff *skb; /* skb we are to transmit next, used for when we 3881da177e4SLinus Torvalds * are transmitting the same one multiple times 3891da177e4SLinus Torvalds */ 39063adc6fbSStephen Hemminger struct net_device *odev; /* The out-going device. 39163adc6fbSStephen Hemminger * Note that the device should have it's 39263adc6fbSStephen Hemminger * pg_info pointer pointing back to this 39363adc6fbSStephen Hemminger * device. 39463adc6fbSStephen Hemminger * Set when the user specifies the out-going 39563adc6fbSStephen Hemminger * device name (not when the inject is 3961da177e4SLinus Torvalds * started as it used to do.) 3971da177e4SLinus Torvalds */ 398593f63b0SEric Dumazet char odevname[32]; 3991da177e4SLinus Torvalds struct flow_state *flows; 40095c96174SEric Dumazet unsigned int cflows; /* Concurrent flows (config) */ 40195c96174SEric Dumazet unsigned int lflow; /* Flow length (config) */ 40295c96174SEric Dumazet unsigned int nflows; /* accumulated flows (stats) */ 40395c96174SEric Dumazet unsigned int curfl; /* current sequenced flow (state)*/ 40445b270f8SRobert Olsson 40545b270f8SRobert Olsson u16 queue_map_min; 40645b270f8SRobert Olsson u16 queue_map_max; 4079e50e3acSJohn Fastabend __u32 skb_priority; /* skb priority field */ 40838b2cf29SAlexei Starovoitov unsigned int burst; /* number of duplicated packets to burst */ 409e99b99b4SRobert Olsson int node; /* Memory node */ 41045b270f8SRobert Olsson 411a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 412a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 413a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 414de4aee7dSFan Du __u32 spi; 415b6ca8bd5SDavid Miller struct xfrm_dst xdst; 416cf93d47eSFan Du struct dst_ops dstops; 417a553e4a6SJamal Hadi Salim #endif 41839df232fSStephen Hemminger char result[512]; 4191da177e4SLinus Torvalds }; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds struct pktgen_hdr { 422252e3346SAl Viro __be32 pgh_magic; 423252e3346SAl Viro __be32 seq_num; 424252e3346SAl Viro __be32 tv_sec; 425252e3346SAl Viro __be32 tv_usec; 4261da177e4SLinus Torvalds }; 4271da177e4SLinus Torvalds 4284e58a027SCong Wang 429c7d03a00SAlexey Dobriyan static unsigned int pg_net_id __read_mostly; 4304e58a027SCong Wang 4314e58a027SCong Wang struct pktgen_net { 4324e58a027SCong Wang struct net *net; 4334e58a027SCong Wang struct proc_dir_entry *proc_dir; 4344e58a027SCong Wang struct list_head pktgen_threads; 4354e58a027SCong Wang bool pktgen_exiting; 4364e58a027SCong Wang }; 437551eaff1SEric Dumazet 4381da177e4SLinus Torvalds struct pktgen_thread { 4399a0b1e8bSEric Dumazet struct mutex if_lock; /* for list of devices */ 440c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 441cdcdbe0bSLuiz Capitulino struct list_head th_list; 442ee74baa7SDavid S. Miller struct task_struct *tsk; 4431da177e4SLinus Torvalds char result[512]; 4441da177e4SLinus Torvalds 44563adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 44663adc6fbSStephen Hemminger stop ifs etc. */ 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds u32 control; 4491da177e4SLinus Torvalds int cpu; 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds wait_queue_head_t queue; 452d3ede327SDenis V. Lunev struct completion start_done; 4534e58a027SCong Wang struct pktgen_net *net; 4541da177e4SLinus Torvalds }; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds #define REMOVE 1 4571da177e4SLinus Torvalds #define FIND 0 4581da177e4SLinus Torvalds 459c3d2f52dSStephen Hemminger static const char version[] = 460f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 461f9467eaeSJoe Perches "Version: " VERSION "\n"; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4641da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 465222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4663e984840SEric Dumazet const char *ifname, bool exact); 4671da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4684e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn); 4694e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn); 470*cda9de0bSYejune Deng static void pktgen_stop_all_threads(struct pktgen_net *pn); 4713bda06a3SStephen Hemminger 4721da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4731da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 47439df232fSStephen Hemminger 4751da177e4SLinus Torvalds /* Module parameters, defaults. */ 47665c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 47765c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 47865c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 47965c5b786SStephen Hemminger static int debug __read_mostly; 4801da177e4SLinus Torvalds 481222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 4841da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 4851da177e4SLinus Torvalds }; 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds /* 4881da177e4SLinus Torvalds * /proc handling functions 4891da177e4SLinus Torvalds * 4901da177e4SLinus Torvalds */ 4911da177e4SLinus Torvalds 492d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 493d50a6b56SStephen Hemminger { 494c3d2f52dSStephen Hemminger seq_puts(seq, version); 495d50a6b56SStephen Hemminger return 0; 496d50a6b56SStephen Hemminger } 4971da177e4SLinus Torvalds 498d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 4991da177e4SLinus Torvalds size_t count, loff_t *ppos) 5001da177e4SLinus Torvalds { 501d50a6b56SStephen Hemminger char data[128]; 5024e58a027SCong Wang struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id); 5031da177e4SLinus Torvalds 50409455747SMathias Krause if (!capable(CAP_NET_ADMIN)) 50509455747SMathias Krause return -EPERM; 5061da177e4SLinus Torvalds 50720b0c718SMathias Krause if (count == 0) 50820b0c718SMathias Krause return -EINVAL; 50920b0c718SMathias Krause 510d50a6b56SStephen Hemminger if (count > sizeof(data)) 511d50a6b56SStephen Hemminger count = sizeof(data); 5121da177e4SLinus Torvalds 51309455747SMathias Krause if (copy_from_user(data, buf, count)) 51409455747SMathias Krause return -EFAULT; 51509455747SMathias Krause 51620b0c718SMathias Krause data[count - 1] = 0; /* Strip trailing '\n' and terminate string */ 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds if (!strcmp(data, "stop")) 519*cda9de0bSYejune Deng pktgen_stop_all_threads(pn); 5201da177e4SLinus Torvalds else if (!strcmp(data, "start")) 5214e58a027SCong Wang pktgen_run_all_threads(pn); 522eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 5234e58a027SCong Wang pktgen_reset_all_threads(pn); 5241da177e4SLinus Torvalds else 52540207264SJesper Dangaard Brouer return -EINVAL; 5261da177e4SLinus Torvalds 52709455747SMathias Krause return count; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 530d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5311da177e4SLinus Torvalds { 532d9dda78bSAl Viro return single_open(file, pgctrl_show, PDE_DATA(inode)); 533d50a6b56SStephen Hemminger } 534d50a6b56SStephen Hemminger 53597a32539SAlexey Dobriyan static const struct proc_ops pktgen_proc_ops = { 53697a32539SAlexey Dobriyan .proc_open = pgctrl_open, 53797a32539SAlexey Dobriyan .proc_read = seq_read, 53897a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 53997a32539SAlexey Dobriyan .proc_write = pgctrl_write, 54097a32539SAlexey Dobriyan .proc_release = single_release, 541d50a6b56SStephen Hemminger }; 542d50a6b56SStephen Hemminger 543d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 544d50a6b56SStephen Hemminger { 545648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 546fd29cf72SStephen Hemminger ktime_t stopped; 54799c6d3d2SDmitry Safonov unsigned int i; 548fd29cf72SStephen Hemminger u64 idle; 5491da177e4SLinus Torvalds 550222f1806SLuiz Capitulino seq_printf(seq, 551222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 552222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 553222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5541da177e4SLinus Torvalds 555222f1806SLuiz Capitulino seq_printf(seq, 556fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 557fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 558593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5591da177e4SLinus Torvalds 560222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 561222f1806SLuiz Capitulino pkt_dev->lflow); 5621da177e4SLinus Torvalds 56345b270f8SRobert Olsson seq_printf(seq, 56445b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 56545b270f8SRobert Olsson pkt_dev->queue_map_min, 56645b270f8SRobert Olsson pkt_dev->queue_map_max); 56745b270f8SRobert Olsson 5689e50e3acSJohn Fastabend if (pkt_dev->skb_priority) 5699e50e3acSJohn Fastabend seq_printf(seq, " skb_priority: %u\n", 5709e50e3acSJohn Fastabend pkt_dev->skb_priority); 5719e50e3acSJohn Fastabend 5721da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 573222f1806SLuiz Capitulino seq_printf(seq, 57447a0200dSAlexey Dobriyan " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" 57547a0200dSAlexey Dobriyan " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", 57647a0200dSAlexey Dobriyan &pkt_dev->in6_saddr, 57747a0200dSAlexey Dobriyan &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, 57847a0200dSAlexey Dobriyan &pkt_dev->in6_daddr, 57947a0200dSAlexey Dobriyan &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); 58063adc6fbSStephen Hemminger } else { 581222f1806SLuiz Capitulino seq_printf(seq, 58263adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 58363adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 58463adc6fbSStephen Hemminger seq_printf(seq, 58563adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 58663adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 58763adc6fbSStephen Hemminger } 5881da177e4SLinus Torvalds 589d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 5901da177e4SLinus Torvalds 591e174961cSJohannes Berg seq_printf(seq, "%pM ", 592e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 593e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5941da177e4SLinus Torvalds 59597dc48e2SThomas Graf seq_puts(seq, "dst_mac: "); 596e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 5971da177e4SLinus Torvalds 598222f1806SLuiz Capitulino seq_printf(seq, 59963adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 60063adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 601222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 602222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 6031da177e4SLinus Torvalds 604222f1806SLuiz Capitulino seq_printf(seq, 605ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 6061da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 6071da177e4SLinus Torvalds 608ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 60997dc48e2SThomas Graf seq_puts(seq, " mpls: "); 610ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 611ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 612ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 613ca6549afSSteven Whitehouse } 614ca6549afSSteven Whitehouse 61563adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 61634954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 61763adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 61863adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 61934954ddcSFrancesco Fondelli 62063adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 62134954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 62263adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 62363adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 62434954ddcSFrancesco Fondelli 62563adc6fbSStephen Hemminger if (pkt_dev->tos) 6261ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6271ca7768cSFrancesco Fondelli 62863adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6291ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6301ca7768cSFrancesco Fondelli 63138b2cf29SAlexei Starovoitov if (pkt_dev->burst > 1) 63238b2cf29SAlexei Starovoitov seq_printf(seq, " burst: %d\n", pkt_dev->burst); 63338b2cf29SAlexei Starovoitov 634e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 635e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 636e99b99b4SRobert Olsson 63762f64aedSAlexei Starovoitov if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) 63862f64aedSAlexei Starovoitov seq_puts(seq, " xmit_mode: netif_receive\n"); 6390967f244SJohn Fastabend else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) 6400967f244SJohn Fastabend seq_puts(seq, " xmit_mode: xmit_queue\n"); 64162f64aedSAlexei Starovoitov 64297dc48e2SThomas Graf seq_puts(seq, " Flags: "); 643ca6549afSSteven Whitehouse 64499c6d3d2SDmitry Safonov for (i = 0; i < NR_PKT_FLAGS; i++) { 64599c6d3d2SDmitry Safonov if (i == F_FLOW_SEQ) 64699c6d3d2SDmitry Safonov if (!pkt_dev->cflows) 64799c6d3d2SDmitry Safonov continue; 6481da177e4SLinus Torvalds 64999c6d3d2SDmitry Safonov if (pkt_dev->flags & (1 << i)) 65099c6d3d2SDmitry Safonov seq_printf(seq, "%s ", pkt_flag_names[i]); 65199c6d3d2SDmitry Safonov else if (i == F_FLOW_SEQ) 65297dc48e2SThomas Graf seq_puts(seq, "FLOW_RND "); 653007a531bSJamal Hadi Salim 654a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 65599c6d3d2SDmitry Safonov if (i == F_IPSEC && pkt_dev->spi) 6568101328bSFan Du seq_printf(seq, "spi:%u", pkt_dev->spi); 657a553e4a6SJamal Hadi Salim #endif 65899c6d3d2SDmitry Safonov } 659e99b99b4SRobert Olsson 660d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 6611da177e4SLinus Torvalds 662fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 663398f382cSDaniel Borkmann stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at; 664fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 665fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 6661da177e4SLinus Torvalds 667222f1806SLuiz Capitulino seq_printf(seq, 668fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 6691da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 670fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 671fd29cf72SStephen Hemminger 672fd29cf72SStephen Hemminger seq_printf(seq, 673fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 674fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 675fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 676fd29cf72SStephen Hemminger (unsigned long long) idle); 6771da177e4SLinus Torvalds 678222f1806SLuiz Capitulino seq_printf(seq, 679222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 680d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 681d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 68447a0200dSAlexey Dobriyan seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", 68547a0200dSAlexey Dobriyan &pkt_dev->cur_in6_saddr, 68647a0200dSAlexey Dobriyan &pkt_dev->cur_in6_daddr); 687222f1806SLuiz Capitulino } else 6880373a946SAmerigo Wang seq_printf(seq, " cur_saddr: %pI4 cur_daddr: %pI4\n", 6890373a946SAmerigo Wang &pkt_dev->cur_saddr, &pkt_dev->cur_daddr); 6901da177e4SLinus Torvalds 691d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 6921da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 6931da177e4SLinus Torvalds 69445b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 69545b270f8SRobert Olsson 696d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds if (pkt_dev->result[0]) 699d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7001da177e4SLinus Torvalds else 70197dc48e2SThomas Graf seq_puts(seq, "Result: Idle\n"); 7021da177e4SLinus Torvalds 703d50a6b56SStephen Hemminger return 0; 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 706ca6549afSSteven Whitehouse 70763adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 70863adc6fbSStephen Hemminger __u32 *num) 709ca6549afSSteven Whitehouse { 710ca6549afSSteven Whitehouse int i = 0; 711ca6549afSSteven Whitehouse *num = 0; 712ca6549afSSteven Whitehouse 7131ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 71482fd5b5dSAndy Shevchenko int value; 715ca6549afSSteven Whitehouse char c; 716ca6549afSSteven Whitehouse *num <<= 4; 717ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 718ca6549afSSteven Whitehouse return -EFAULT; 71982fd5b5dSAndy Shevchenko value = hex_to_bin(c); 72082fd5b5dSAndy Shevchenko if (value >= 0) 72182fd5b5dSAndy Shevchenko *num |= value; 722ca6549afSSteven Whitehouse else 723ca6549afSSteven Whitehouse break; 724ca6549afSSteven Whitehouse } 725ca6549afSSteven Whitehouse return i; 726ca6549afSSteven Whitehouse } 727ca6549afSSteven Whitehouse 728222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 729222f1806SLuiz Capitulino unsigned int maxlen) 7301da177e4SLinus Torvalds { 7311da177e4SLinus Torvalds int i; 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7341da177e4SLinus Torvalds char c; 7351da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7361da177e4SLinus Torvalds return -EFAULT; 7371da177e4SLinus Torvalds switch (c) { 7381da177e4SLinus Torvalds case '\"': 7391da177e4SLinus Torvalds case '\n': 7401da177e4SLinus Torvalds case '\r': 7411da177e4SLinus Torvalds case '\t': 7421da177e4SLinus Torvalds case ' ': 7431da177e4SLinus Torvalds case '=': 7441da177e4SLinus Torvalds break; 7451da177e4SLinus Torvalds default: 7461da177e4SLinus Torvalds goto done; 7473ff50b79SStephen Hemminger } 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds done: 7501da177e4SLinus Torvalds return i; 7511da177e4SLinus Torvalds } 7521da177e4SLinus Torvalds 753bf0813bdSPaul Gortmaker static long num_arg(const char __user *user_buffer, unsigned long maxlen, 754bf0813bdSPaul Gortmaker unsigned long *num) 7551da177e4SLinus Torvalds { 756d6182223SPaul Gortmaker int i; 7571da177e4SLinus Torvalds *num = 0; 7581da177e4SLinus Torvalds 759d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 7601da177e4SLinus Torvalds char c; 7611da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7621da177e4SLinus Torvalds return -EFAULT; 7631da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 7641da177e4SLinus Torvalds *num *= 10; 7651da177e4SLinus Torvalds *num += c - '0'; 7661da177e4SLinus Torvalds } else 7671da177e4SLinus Torvalds break; 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds return i; 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 7731da177e4SLinus Torvalds { 774d6182223SPaul Gortmaker int i; 7751da177e4SLinus Torvalds 776d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 7771da177e4SLinus Torvalds char c; 7781da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7791da177e4SLinus Torvalds return -EFAULT; 7801da177e4SLinus Torvalds switch (c) { 7811da177e4SLinus Torvalds case '\"': 7821da177e4SLinus Torvalds case '\n': 7831da177e4SLinus Torvalds case '\r': 7841da177e4SLinus Torvalds case '\t': 7851da177e4SLinus Torvalds case ' ': 7861da177e4SLinus Torvalds goto done_str; 7871da177e4SLinus Torvalds default: 7881da177e4SLinus Torvalds break; 7893ff50b79SStephen Hemminger } 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds done_str: 7921da177e4SLinus Torvalds return i; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds 795ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 796ca6549afSSteven Whitehouse { 79795c96174SEric Dumazet unsigned int n = 0; 798ca6549afSSteven Whitehouse char c; 799ca6549afSSteven Whitehouse ssize_t i = 0; 800ca6549afSSteven Whitehouse int len; 801ca6549afSSteven Whitehouse 802ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 803ca6549afSSteven Whitehouse do { 804ca6549afSSteven Whitehouse __u32 tmp; 8051ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 806ca6549afSSteven Whitehouse if (len <= 0) 807ca6549afSSteven Whitehouse return len; 808ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 809ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 810ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 811ca6549afSSteven Whitehouse i += len; 812ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 813ca6549afSSteven Whitehouse return -EFAULT; 814ca6549afSSteven Whitehouse i++; 815ca6549afSSteven Whitehouse n++; 816ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 817ca6549afSSteven Whitehouse return -E2BIG; 818ca6549afSSteven Whitehouse } while (c == ','); 819ca6549afSSteven Whitehouse 820ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 821ca6549afSSteven Whitehouse return i; 822ca6549afSSteven Whitehouse } 823ca6549afSSteven Whitehouse 82452e12d5dSDmitry Safonov static __u32 pktgen_read_flag(const char *f, bool *disable) 82552e12d5dSDmitry Safonov { 82652e12d5dSDmitry Safonov __u32 i; 82752e12d5dSDmitry Safonov 82852e12d5dSDmitry Safonov if (f[0] == '!') { 82952e12d5dSDmitry Safonov *disable = true; 83052e12d5dSDmitry Safonov f++; 83152e12d5dSDmitry Safonov } 83252e12d5dSDmitry Safonov 83352e12d5dSDmitry Safonov for (i = 0; i < NR_PKT_FLAGS; i++) { 83452e12d5dSDmitry Safonov if (!IS_ENABLED(CONFIG_XFRM) && i == IPSEC_SHIFT) 83552e12d5dSDmitry Safonov continue; 83652e12d5dSDmitry Safonov 83752e12d5dSDmitry Safonov /* allow only disabling ipv6 flag */ 83852e12d5dSDmitry Safonov if (!*disable && i == IPV6_SHIFT) 83952e12d5dSDmitry Safonov continue; 84052e12d5dSDmitry Safonov 84152e12d5dSDmitry Safonov if (strcmp(f, pkt_flag_names[i]) == 0) 84252e12d5dSDmitry Safonov return 1 << i; 84352e12d5dSDmitry Safonov } 84452e12d5dSDmitry Safonov 84552e12d5dSDmitry Safonov if (strcmp(f, "FLOW_RND") == 0) { 84652e12d5dSDmitry Safonov *disable = !*disable; 84752e12d5dSDmitry Safonov return F_FLOW_SEQ; 84852e12d5dSDmitry Safonov } 84952e12d5dSDmitry Safonov 85052e12d5dSDmitry Safonov return 0; 85152e12d5dSDmitry Safonov } 85252e12d5dSDmitry Safonov 853222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 854222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 855222f1806SLuiz Capitulino loff_t * offset) 8561da177e4SLinus Torvalds { 8578a994a71SJoe Perches struct seq_file *seq = file->private_data; 858d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 859d6182223SPaul Gortmaker int i, max, len; 8601da177e4SLinus Torvalds char name[16], valstr[32]; 8611da177e4SLinus Torvalds unsigned long value = 0; 8621da177e4SLinus Torvalds char *pg_result = NULL; 8631da177e4SLinus Torvalds int tmp = 0; 8641da177e4SLinus Torvalds char buf[128]; 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds if (count < 1) { 869294a0b7fSJoe Perches pr_warn("wrong command format\n"); 8701da177e4SLinus Torvalds return -EINVAL; 8711da177e4SLinus Torvalds } 8721da177e4SLinus Torvalds 873d6182223SPaul Gortmaker max = count; 874d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 8751da177e4SLinus Torvalds if (tmp < 0) { 876294a0b7fSJoe Perches pr_warn("illegal format\n"); 8771da177e4SLinus Torvalds return tmp; 8781da177e4SLinus Torvalds } 879d6182223SPaul Gortmaker i = tmp; 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds /* Read variable name */ 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 88463adc6fbSStephen Hemminger if (len < 0) 885222f1806SLuiz Capitulino return len; 88663adc6fbSStephen Hemminger 8871da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 8881da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 8891da177e4SLinus Torvalds return -EFAULT; 8901da177e4SLinus Torvalds i += len; 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds max = count - i; 8931da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 8941da177e4SLinus Torvalds if (len < 0) 8951da177e4SLinus Torvalds return len; 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds i += len; 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds if (debug) { 900a870a02cSArnd Bergmann size_t copy = min_t(size_t, count + 1, 1024); 901a870a02cSArnd Bergmann char *tp = strndup_user(user_buffer, copy); 902a870a02cSArnd Bergmann 903a870a02cSArnd Bergmann if (IS_ERR(tp)) 904a870a02cSArnd Bergmann return PTR_ERR(tp); 905a870a02cSArnd Bergmann 906a870a02cSArnd Bergmann pr_debug("%s,%zu buffer -:%s:-\n", name, count, tp); 90729d1df72SGustavo A. R. Silva kfree(tp); 9081da177e4SLinus Torvalds } 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9111da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 91263adc6fbSStephen Hemminger if (len < 0) 913222f1806SLuiz Capitulino return len; 91463adc6fbSStephen Hemminger 9151da177e4SLinus Torvalds i += len; 9161da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9171da177e4SLinus Torvalds value = 14 + 20 + 8; 9181da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9191da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9201da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9211da177e4SLinus Torvalds } 92232be425bSYe Bin sprintf(pg_result, "OK: min_pkt_size=%d", 923222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9241da177e4SLinus Torvalds return count; 9251da177e4SLinus Torvalds } 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9281da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 92963adc6fbSStephen Hemminger if (len < 0) 930222f1806SLuiz Capitulino return len; 93163adc6fbSStephen Hemminger 9321da177e4SLinus Torvalds i += len; 9331da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9341da177e4SLinus Torvalds value = 14 + 20 + 8; 9351da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9361da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9371da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9381da177e4SLinus Torvalds } 93932be425bSYe Bin sprintf(pg_result, "OK: max_pkt_size=%d", 940222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9411da177e4SLinus Torvalds return count; 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* Shortcut for min = max */ 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9471da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 94863adc6fbSStephen Hemminger if (len < 0) 949222f1806SLuiz Capitulino return len; 95063adc6fbSStephen Hemminger 9511da177e4SLinus Torvalds i += len; 9521da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9531da177e4SLinus Torvalds value = 14 + 20 + 8; 9541da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9551da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9561da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9571da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9581da177e4SLinus Torvalds } 95932be425bSYe Bin sprintf(pg_result, "OK: pkt_size=%d", pkt_dev->min_pkt_size); 9601da177e4SLinus Torvalds return count; 9611da177e4SLinus Torvalds } 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9641da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 96563adc6fbSStephen Hemminger if (len < 0) 966222f1806SLuiz Capitulino return len; 96763adc6fbSStephen Hemminger 9681da177e4SLinus Torvalds i += len; 9691da177e4SLinus Torvalds debug = value; 9701da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9711da177e4SLinus Torvalds return count; 9721da177e4SLinus Torvalds } 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9751da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 97663adc6fbSStephen Hemminger if (len < 0) 977222f1806SLuiz Capitulino return len; 97863adc6fbSStephen Hemminger 9791da177e4SLinus Torvalds i += len; 9801da177e4SLinus Torvalds pkt_dev->nfrags = value; 98132be425bSYe Bin sprintf(pg_result, "OK: frags=%d", pkt_dev->nfrags); 9821da177e4SLinus Torvalds return count; 9831da177e4SLinus Torvalds } 9841da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 9851da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 98663adc6fbSStephen Hemminger if (len < 0) 987222f1806SLuiz Capitulino return len; 98863adc6fbSStephen Hemminger 9891da177e4SLinus Torvalds i += len; 990fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 991fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 992fd29cf72SStephen Hemminger else 9939240d715SEric Dumazet pkt_dev->delay = (u64)value; 994fd29cf72SStephen Hemminger 995fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 996fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 9971da177e4SLinus Torvalds return count; 9981da177e4SLinus Torvalds } 99943d28b65SDaniel Turull if (!strcmp(name, "rate")) { 100043d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 100143d28b65SDaniel Turull if (len < 0) 100243d28b65SDaniel Turull return len; 100343d28b65SDaniel Turull 100443d28b65SDaniel Turull i += len; 100543d28b65SDaniel Turull if (!value) 100643d28b65SDaniel Turull return len; 100743d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 100843d28b65SDaniel Turull if (debug) 1009f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 101043d28b65SDaniel Turull 101143d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 101243d28b65SDaniel Turull return count; 101343d28b65SDaniel Turull } 101443d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 101543d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 101643d28b65SDaniel Turull if (len < 0) 101743d28b65SDaniel Turull return len; 101843d28b65SDaniel Turull 101943d28b65SDaniel Turull i += len; 102043d28b65SDaniel Turull if (!value) 102143d28b65SDaniel Turull return len; 102243d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 102343d28b65SDaniel Turull if (debug) 1024f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 102543d28b65SDaniel Turull 102643d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 102743d28b65SDaniel Turull return count; 102843d28b65SDaniel Turull } 10291da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10301da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 103163adc6fbSStephen Hemminger if (len < 0) 1032222f1806SLuiz Capitulino return len; 103363adc6fbSStephen Hemminger 10341da177e4SLinus Torvalds i += len; 10351da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10361da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10371da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10401da177e4SLinus Torvalds return count; 10411da177e4SLinus Torvalds } 10421da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10431da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 104463adc6fbSStephen Hemminger if (len < 0) 1045222f1806SLuiz Capitulino return len; 104663adc6fbSStephen Hemminger 10471da177e4SLinus Torvalds i += len; 10481da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10491da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10501da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10511da177e4SLinus Torvalds } 10521da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10531da177e4SLinus Torvalds return count; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10561da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 105763adc6fbSStephen Hemminger if (len < 0) 1058222f1806SLuiz Capitulino return len; 105963adc6fbSStephen Hemminger 10601da177e4SLinus Torvalds i += len; 10611da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10621da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10631da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10641da177e4SLinus Torvalds } 10651da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10661da177e4SLinus Torvalds return count; 10671da177e4SLinus Torvalds } 10681da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10691da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107063adc6fbSStephen Hemminger if (len < 0) 1071222f1806SLuiz Capitulino return len; 107263adc6fbSStephen Hemminger 10731da177e4SLinus Torvalds i += len; 10741da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10751da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10761da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10771da177e4SLinus Torvalds } 10781da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10791da177e4SLinus Torvalds return count; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10821da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 108363adc6fbSStephen Hemminger if (len < 0) 1084222f1806SLuiz Capitulino return len; 1085d8873315SNeil Horman if ((value > 0) && 108662f64aedSAlexei Starovoitov ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) || 108762f64aedSAlexei Starovoitov !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) 1088d8873315SNeil Horman return -ENOTSUPP; 10891da177e4SLinus Torvalds i += len; 10901da177e4SLinus Torvalds pkt_dev->clone_skb = value; 10911da177e4SLinus Torvalds 10921da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10931da177e4SLinus Torvalds return count; 10941da177e4SLinus Torvalds } 10951da177e4SLinus Torvalds if (!strcmp(name, "count")) { 10961da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109763adc6fbSStephen Hemminger if (len < 0) 1098222f1806SLuiz Capitulino return len; 109963adc6fbSStephen Hemminger 11001da177e4SLinus Torvalds i += len; 11011da177e4SLinus Torvalds pkt_dev->count = value; 11021da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 11031da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 11041da177e4SLinus Torvalds return count; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 11071da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 110863adc6fbSStephen Hemminger if (len < 0) 1109222f1806SLuiz Capitulino return len; 111063adc6fbSStephen Hemminger 11111da177e4SLinus Torvalds i += len; 11121da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 11131da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11141da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11151da177e4SLinus Torvalds } 1116222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1117222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11181da177e4SLinus Torvalds return count; 11191da177e4SLinus Torvalds } 11201da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11211da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 112263adc6fbSStephen Hemminger if (len < 0) 1123222f1806SLuiz Capitulino return len; 112463adc6fbSStephen Hemminger 11251da177e4SLinus Torvalds i += len; 11261da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11271da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11281da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11291da177e4SLinus Torvalds } 1130222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1131222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11321da177e4SLinus Torvalds return count; 11331da177e4SLinus Torvalds } 113438b2cf29SAlexei Starovoitov if (!strcmp(name, "burst")) { 113538b2cf29SAlexei Starovoitov len = num_arg(&user_buffer[i], 10, &value); 113638b2cf29SAlexei Starovoitov if (len < 0) 113738b2cf29SAlexei Starovoitov return len; 113838b2cf29SAlexei Starovoitov 113938b2cf29SAlexei Starovoitov i += len; 11400967f244SJohn Fastabend if ((value > 1) && 11410967f244SJohn Fastabend ((pkt_dev->xmit_mode == M_QUEUE_XMIT) || 11420967f244SJohn Fastabend ((pkt_dev->xmit_mode == M_START_XMIT) && 11430967f244SJohn Fastabend (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))))) 114452d6c8c6SEric Dumazet return -ENOTSUPP; 114538b2cf29SAlexei Starovoitov pkt_dev->burst = value < 1 ? 1 : value; 114632be425bSYe Bin sprintf(pg_result, "OK: burst=%u", pkt_dev->burst); 114738b2cf29SAlexei Starovoitov return count; 114838b2cf29SAlexei Starovoitov } 1149e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1150e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1151e99b99b4SRobert Olsson if (len < 0) 1152e99b99b4SRobert Olsson return len; 1153e99b99b4SRobert Olsson 1154e99b99b4SRobert Olsson i += len; 1155e99b99b4SRobert Olsson 1156e99b99b4SRobert Olsson if (node_possible(value)) { 1157e99b99b4SRobert Olsson pkt_dev->node = value; 1158e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 115926ad7879SEric Dumazet if (pkt_dev->page) { 116026ad7879SEric Dumazet put_page(pkt_dev->page); 116126ad7879SEric Dumazet pkt_dev->page = NULL; 116226ad7879SEric Dumazet } 1163e99b99b4SRobert Olsson } 1164e99b99b4SRobert Olsson else 1165e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1166e99b99b4SRobert Olsson return count; 1167e99b99b4SRobert Olsson } 116862f64aedSAlexei Starovoitov if (!strcmp(name, "xmit_mode")) { 116962f64aedSAlexei Starovoitov char f[32]; 117062f64aedSAlexei Starovoitov 117162f64aedSAlexei Starovoitov memset(f, 0, 32); 117262f64aedSAlexei Starovoitov len = strn_len(&user_buffer[i], sizeof(f) - 1); 117362f64aedSAlexei Starovoitov if (len < 0) 117462f64aedSAlexei Starovoitov return len; 117562f64aedSAlexei Starovoitov 117662f64aedSAlexei Starovoitov if (copy_from_user(f, &user_buffer[i], len)) 117762f64aedSAlexei Starovoitov return -EFAULT; 117862f64aedSAlexei Starovoitov i += len; 117962f64aedSAlexei Starovoitov 118062f64aedSAlexei Starovoitov if (strcmp(f, "start_xmit") == 0) { 118162f64aedSAlexei Starovoitov pkt_dev->xmit_mode = M_START_XMIT; 118262f64aedSAlexei Starovoitov } else if (strcmp(f, "netif_receive") == 0) { 118362f64aedSAlexei Starovoitov /* clone_skb set earlier, not supported in this mode */ 118462f64aedSAlexei Starovoitov if (pkt_dev->clone_skb > 0) 118562f64aedSAlexei Starovoitov return -ENOTSUPP; 118662f64aedSAlexei Starovoitov 118762f64aedSAlexei Starovoitov pkt_dev->xmit_mode = M_NETIF_RECEIVE; 11889eea9222SAlexei Starovoitov 11899eea9222SAlexei Starovoitov /* make sure new packet is allocated every time 11909eea9222SAlexei Starovoitov * pktgen_xmit() is called 11919eea9222SAlexei Starovoitov */ 11929eea9222SAlexei Starovoitov pkt_dev->last_ok = 1; 11939eea9222SAlexei Starovoitov 11949eea9222SAlexei Starovoitov /* override clone_skb if user passed default value 11959eea9222SAlexei Starovoitov * at module loading time 11969eea9222SAlexei Starovoitov */ 11979eea9222SAlexei Starovoitov pkt_dev->clone_skb = 0; 11980967f244SJohn Fastabend } else if (strcmp(f, "queue_xmit") == 0) { 11990967f244SJohn Fastabend pkt_dev->xmit_mode = M_QUEUE_XMIT; 12000967f244SJohn Fastabend pkt_dev->last_ok = 1; 120162f64aedSAlexei Starovoitov } else { 120262f64aedSAlexei Starovoitov sprintf(pg_result, 120362f64aedSAlexei Starovoitov "xmit_mode -:%s:- unknown\nAvailable modes: %s", 120462f64aedSAlexei Starovoitov f, "start_xmit, netif_receive\n"); 120562f64aedSAlexei Starovoitov return count; 120662f64aedSAlexei Starovoitov } 120762f64aedSAlexei Starovoitov sprintf(pg_result, "OK: xmit_mode=%s", f); 120862f64aedSAlexei Starovoitov return count; 120962f64aedSAlexei Starovoitov } 12101da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 121152e12d5dSDmitry Safonov __u32 flag; 12121da177e4SLinus Torvalds char f[32]; 121352e12d5dSDmitry Safonov bool disable = false; 121452e12d5dSDmitry Safonov 12151da177e4SLinus Torvalds memset(f, 0, 32); 12161da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 121763adc6fbSStephen Hemminger if (len < 0) 1218222f1806SLuiz Capitulino return len; 121963adc6fbSStephen Hemminger 12201da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 12211da177e4SLinus Torvalds return -EFAULT; 12221da177e4SLinus Torvalds i += len; 12231da177e4SLinus Torvalds 122452e12d5dSDmitry Safonov flag = pktgen_read_flag(f, &disable); 12251da177e4SLinus Torvalds 122652e12d5dSDmitry Safonov if (flag) { 122752e12d5dSDmitry Safonov if (disable) 122852e12d5dSDmitry Safonov pkt_dev->flags &= ~flag; 122952e12d5dSDmitry Safonov else 123052e12d5dSDmitry Safonov pkt_dev->flags |= flag; 123152e12d5dSDmitry Safonov } else { 1232222f1806SLuiz Capitulino sprintf(pg_result, 1233222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12341da177e4SLinus Torvalds f, 12351ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 123672f8e06fSMathias Krause "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, " 123772f8e06fSMathias Krause "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, " 123872f8e06fSMathias Krause "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, " 1239afb84b62SJesper Dangaard Brouer "NO_TIMESTAMP, " 124072f8e06fSMathias Krause #ifdef CONFIG_XFRM 124172f8e06fSMathias Krause "IPSEC, " 124272f8e06fSMathias Krause #endif 124372f8e06fSMathias Krause "NODE_ALLOC\n"); 12441da177e4SLinus Torvalds return count; 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12471da177e4SLinus Torvalds return count; 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12501da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 125163adc6fbSStephen Hemminger if (len < 0) 1252222f1806SLuiz Capitulino return len; 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12551da177e4SLinus Torvalds return -EFAULT; 12561da177e4SLinus Torvalds buf[len] = 0; 12571da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12581da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 1259f15f084fSJakub Kicinski strcpy(pkt_dev->dst_min, buf); 12601da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12611da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12621da177e4SLinus Torvalds } 12631da177e4SLinus Torvalds if (debug) 1264f342cda7SJoe Perches pr_debug("dst_min set to: %s\n", pkt_dev->dst_min); 12651da177e4SLinus Torvalds i += len; 12661da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12671da177e4SLinus Torvalds return count; 12681da177e4SLinus Torvalds } 12691da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12701da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 127163adc6fbSStephen Hemminger if (len < 0) 1272222f1806SLuiz Capitulino return len; 127363adc6fbSStephen Hemminger 12741da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12751da177e4SLinus Torvalds return -EFAULT; 12761da177e4SLinus Torvalds buf[len] = 0; 12771da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 12781da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 1279f15f084fSJakub Kicinski strcpy(pkt_dev->dst_max, buf); 12801da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12811da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 12821da177e4SLinus Torvalds } 12831da177e4SLinus Torvalds if (debug) 1284f342cda7SJoe Perches pr_debug("dst_max set to: %s\n", pkt_dev->dst_max); 12851da177e4SLinus Torvalds i += len; 12861da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12871da177e4SLinus Torvalds return count; 12881da177e4SLinus Torvalds } 12891da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 12901da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1291222f1806SLuiz Capitulino if (len < 0) 1292222f1806SLuiz Capitulino return len; 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12971da177e4SLinus Torvalds return -EFAULT; 12981da177e4SLinus Torvalds buf[len] = 0; 12991da177e4SLinus Torvalds 1300c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL); 130147a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); 13021da177e4SLinus Torvalds 13034e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr; 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds if (debug) 1306f342cda7SJoe Perches pr_debug("dst6 set to: %s\n", buf); 13071da177e4SLinus Torvalds 13081da177e4SLinus Torvalds i += len; 13091da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13101da177e4SLinus Torvalds return count; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13131da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1314222f1806SLuiz Capitulino if (len < 0) 1315222f1806SLuiz Capitulino return len; 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13181da177e4SLinus Torvalds 13191da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13201da177e4SLinus Torvalds return -EFAULT; 13211da177e4SLinus Torvalds buf[len] = 0; 13221da177e4SLinus Torvalds 1323c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL); 132447a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); 13251da177e4SLinus Torvalds 13264e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr; 13271da177e4SLinus Torvalds if (debug) 1328f342cda7SJoe Perches pr_debug("dst6_min set to: %s\n", buf); 13291da177e4SLinus Torvalds 13301da177e4SLinus Torvalds i += len; 13311da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13321da177e4SLinus Torvalds return count; 13331da177e4SLinus Torvalds } 13341da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13351da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1336222f1806SLuiz Capitulino if (len < 0) 1337222f1806SLuiz Capitulino return len; 13381da177e4SLinus Torvalds 13391da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13421da177e4SLinus Torvalds return -EFAULT; 13431da177e4SLinus Torvalds buf[len] = 0; 13441da177e4SLinus Torvalds 1345c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL); 134647a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds if (debug) 1349f342cda7SJoe Perches pr_debug("dst6_max set to: %s\n", buf); 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds i += len; 13521da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13531da177e4SLinus Torvalds return count; 13541da177e4SLinus Torvalds } 13551da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13561da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1357222f1806SLuiz Capitulino if (len < 0) 1358222f1806SLuiz Capitulino return len; 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13631da177e4SLinus Torvalds return -EFAULT; 13641da177e4SLinus Torvalds buf[len] = 0; 13651da177e4SLinus Torvalds 1366c468fb13SAmerigo Wang in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL); 136747a0200dSAlexey Dobriyan snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); 13681da177e4SLinus Torvalds 13694e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr; 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds if (debug) 1372f342cda7SJoe Perches pr_debug("src6 set to: %s\n", buf); 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds i += len; 13751da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 13761da177e4SLinus Torvalds return count; 13771da177e4SLinus Torvalds } 13781da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 13791da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 138063adc6fbSStephen Hemminger if (len < 0) 1381222f1806SLuiz Capitulino return len; 138263adc6fbSStephen Hemminger 13831da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13841da177e4SLinus Torvalds return -EFAULT; 13851da177e4SLinus Torvalds buf[len] = 0; 13861da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 13871da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 1388f15f084fSJakub Kicinski strcpy(pkt_dev->src_min, buf); 13891da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13901da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 13911da177e4SLinus Torvalds } 13921da177e4SLinus Torvalds if (debug) 1393f342cda7SJoe Perches pr_debug("src_min set to: %s\n", pkt_dev->src_min); 13941da177e4SLinus Torvalds i += len; 13951da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 13961da177e4SLinus Torvalds return count; 13971da177e4SLinus Torvalds } 13981da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 13991da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 140063adc6fbSStephen Hemminger if (len < 0) 1401222f1806SLuiz Capitulino return len; 140263adc6fbSStephen Hemminger 14031da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14041da177e4SLinus Torvalds return -EFAULT; 14051da177e4SLinus Torvalds buf[len] = 0; 14061da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14071da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 1408f15f084fSJakub Kicinski strcpy(pkt_dev->src_max, buf); 14091da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14101da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds if (debug) 1413f342cda7SJoe Perches pr_debug("src_max set to: %s\n", pkt_dev->src_max); 14141da177e4SLinus Torvalds i += len; 14151da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14161da177e4SLinus Torvalds return count; 14171da177e4SLinus Torvalds } 14181da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14191da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 142063adc6fbSStephen Hemminger if (len < 0) 1421222f1806SLuiz Capitulino return len; 142263adc6fbSStephen Hemminger 14231da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14241da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14251da177e4SLinus Torvalds return -EFAULT; 14261da177e4SLinus Torvalds 14274940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->dst_mac)) 14284940fc88SAlexey Dobriyan return -EINVAL; 14291da177e4SLinus Torvalds /* Set up Dest MAC */ 14309ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); 14311da177e4SLinus Torvalds 14324940fc88SAlexey Dobriyan sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); 14331da177e4SLinus Torvalds return count; 14341da177e4SLinus Torvalds } 14351da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14361da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 143763adc6fbSStephen Hemminger if (len < 0) 1438222f1806SLuiz Capitulino return len; 143963adc6fbSStephen Hemminger 14401da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14411da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14421da177e4SLinus Torvalds return -EFAULT; 14431da177e4SLinus Torvalds 14444940fc88SAlexey Dobriyan if (!mac_pton(valstr, pkt_dev->src_mac)) 14454940fc88SAlexey Dobriyan return -EINVAL; 1446ce5d0b47SAdit Ranadive /* Set up Src MAC */ 14479ea08b12SJoe Perches ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); 1448ce5d0b47SAdit Ranadive 14494940fc88SAlexey Dobriyan sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); 14501da177e4SLinus Torvalds return count; 14511da177e4SLinus Torvalds } 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 14541da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 14551da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 14561da177e4SLinus Torvalds return count; 14571da177e4SLinus Torvalds } 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 14601da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 146163adc6fbSStephen Hemminger if (len < 0) 1462222f1806SLuiz Capitulino return len; 146363adc6fbSStephen Hemminger 14641da177e4SLinus Torvalds i += len; 14651da177e4SLinus Torvalds if (value > MAX_CFLOWS) 14661da177e4SLinus Torvalds value = MAX_CFLOWS; 14671da177e4SLinus Torvalds 14681da177e4SLinus Torvalds pkt_dev->cflows = value; 14691da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 14701da177e4SLinus Torvalds return count; 14711da177e4SLinus Torvalds } 14726bae9190SFan Du #ifdef CONFIG_XFRM 1473de4aee7dSFan Du if (!strcmp(name, "spi")) { 1474de4aee7dSFan Du len = num_arg(&user_buffer[i], 10, &value); 1475de4aee7dSFan Du if (len < 0) 1476de4aee7dSFan Du return len; 1477de4aee7dSFan Du 1478de4aee7dSFan Du i += len; 1479de4aee7dSFan Du pkt_dev->spi = value; 1480de4aee7dSFan Du sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); 1481de4aee7dSFan Du return count; 1482de4aee7dSFan Du } 14836bae9190SFan Du #endif 14841da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 14851da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 148663adc6fbSStephen Hemminger if (len < 0) 1487222f1806SLuiz Capitulino return len; 148863adc6fbSStephen Hemminger 14891da177e4SLinus Torvalds i += len; 14901da177e4SLinus Torvalds pkt_dev->lflow = value; 14911da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 14921da177e4SLinus Torvalds return count; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds 149545b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 149645b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 149763adc6fbSStephen Hemminger if (len < 0) 149845b270f8SRobert Olsson return len; 149963adc6fbSStephen Hemminger 150045b270f8SRobert Olsson i += len; 150145b270f8SRobert Olsson pkt_dev->queue_map_min = value; 150245b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 150345b270f8SRobert Olsson return count; 150445b270f8SRobert Olsson } 150545b270f8SRobert Olsson 150645b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 150745b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 150863adc6fbSStephen Hemminger if (len < 0) 150945b270f8SRobert Olsson return len; 151063adc6fbSStephen Hemminger 151145b270f8SRobert Olsson i += len; 151245b270f8SRobert Olsson pkt_dev->queue_map_max = value; 151345b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 151445b270f8SRobert Olsson return count; 151545b270f8SRobert Olsson } 151645b270f8SRobert Olsson 1517ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 151895c96174SEric Dumazet unsigned int n, cnt; 1519cfcabdccSStephen Hemminger 1520ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1521cfcabdccSStephen Hemminger if (len < 0) 1522cfcabdccSStephen Hemminger return len; 1523ca6549afSSteven Whitehouse i += len; 1524cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1525ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1526cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1527ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1528ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 152934954ddcSFrancesco Fondelli 153034954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 153134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 153234954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 153334954ddcSFrancesco Fondelli 153434954ddcSFrancesco Fondelli if (debug) 1535f342cda7SJoe Perches pr_debug("VLAN/SVLAN auto turned off\n"); 153634954ddcSFrancesco Fondelli } 153734954ddcSFrancesco Fondelli return count; 153834954ddcSFrancesco Fondelli } 153934954ddcSFrancesco Fondelli 154034954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 154134954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 154263adc6fbSStephen Hemminger if (len < 0) 154334954ddcSFrancesco Fondelli return len; 154463adc6fbSStephen Hemminger 154534954ddcSFrancesco Fondelli i += len; 154634954ddcSFrancesco Fondelli if (value <= 4095) { 154734954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 154834954ddcSFrancesco Fondelli 154934954ddcSFrancesco Fondelli if (debug) 1550f342cda7SJoe Perches pr_debug("VLAN turned on\n"); 155134954ddcSFrancesco Fondelli 155234954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1553f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 155434954ddcSFrancesco Fondelli 155534954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 155634954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 155734954ddcSFrancesco Fondelli } else { 155834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 155934954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 156034954ddcSFrancesco Fondelli 156134954ddcSFrancesco Fondelli if (debug) 1562f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 156334954ddcSFrancesco Fondelli } 156434954ddcSFrancesco Fondelli return count; 156534954ddcSFrancesco Fondelli } 156634954ddcSFrancesco Fondelli 156734954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 156834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 156963adc6fbSStephen Hemminger if (len < 0) 157034954ddcSFrancesco Fondelli return len; 157163adc6fbSStephen Hemminger 157234954ddcSFrancesco Fondelli i += len; 157334954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 157434954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 157534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 157634954ddcSFrancesco Fondelli } else { 157734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 157834954ddcSFrancesco Fondelli } 157934954ddcSFrancesco Fondelli return count; 158034954ddcSFrancesco Fondelli } 158134954ddcSFrancesco Fondelli 158234954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 158334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 158463adc6fbSStephen Hemminger if (len < 0) 158534954ddcSFrancesco Fondelli return len; 158663adc6fbSStephen Hemminger 158734954ddcSFrancesco Fondelli i += len; 158834954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 158934954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 159034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 159134954ddcSFrancesco Fondelli } else { 159234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 159334954ddcSFrancesco Fondelli } 159434954ddcSFrancesco Fondelli return count; 159534954ddcSFrancesco Fondelli } 159634954ddcSFrancesco Fondelli 159734954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 159834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 159963adc6fbSStephen Hemminger if (len < 0) 160034954ddcSFrancesco Fondelli return len; 160163adc6fbSStephen Hemminger 160234954ddcSFrancesco Fondelli i += len; 160334954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 160434954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 160534954ddcSFrancesco Fondelli 160634954ddcSFrancesco Fondelli if (debug) 1607f342cda7SJoe Perches pr_debug("SVLAN turned on\n"); 160834954ddcSFrancesco Fondelli 160934954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 1610f342cda7SJoe Perches pr_debug("MPLS auto turned off\n"); 161134954ddcSFrancesco Fondelli 161234954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 161334954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 161434954ddcSFrancesco Fondelli } else { 161534954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 161634954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 161734954ddcSFrancesco Fondelli 161834954ddcSFrancesco Fondelli if (debug) 1619f342cda7SJoe Perches pr_debug("VLAN/SVLAN turned off\n"); 162034954ddcSFrancesco Fondelli } 162134954ddcSFrancesco Fondelli return count; 162234954ddcSFrancesco Fondelli } 162334954ddcSFrancesco Fondelli 162434954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 162534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 162663adc6fbSStephen Hemminger if (len < 0) 162734954ddcSFrancesco Fondelli return len; 162863adc6fbSStephen Hemminger 162934954ddcSFrancesco Fondelli i += len; 163034954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 163134954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 163234954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 163334954ddcSFrancesco Fondelli } else { 163434954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 163534954ddcSFrancesco Fondelli } 163634954ddcSFrancesco Fondelli return count; 163734954ddcSFrancesco Fondelli } 163834954ddcSFrancesco Fondelli 163934954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 164034954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 164163adc6fbSStephen Hemminger if (len < 0) 164234954ddcSFrancesco Fondelli return len; 164363adc6fbSStephen Hemminger 164434954ddcSFrancesco Fondelli i += len; 164534954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 164634954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 164734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 164834954ddcSFrancesco Fondelli } else { 164934954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 165034954ddcSFrancesco Fondelli } 1651ca6549afSSteven Whitehouse return count; 1652ca6549afSSteven Whitehouse } 1653ca6549afSSteven Whitehouse 16541ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16551ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16561ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 165763adc6fbSStephen Hemminger if (len < 0) 16581ca7768cSFrancesco Fondelli return len; 165963adc6fbSStephen Hemminger 16601ca7768cSFrancesco Fondelli i += len; 16611ca7768cSFrancesco Fondelli if (len == 2) { 16621ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16631ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16641ca7768cSFrancesco Fondelli } else { 16651ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 16661ca7768cSFrancesco Fondelli } 16671ca7768cSFrancesco Fondelli return count; 16681ca7768cSFrancesco Fondelli } 16691ca7768cSFrancesco Fondelli 16701ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 16711ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16721ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 167363adc6fbSStephen Hemminger if (len < 0) 16741ca7768cSFrancesco Fondelli return len; 167563adc6fbSStephen Hemminger 16761ca7768cSFrancesco Fondelli i += len; 16771ca7768cSFrancesco Fondelli if (len == 2) { 16781ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 16791ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 16801ca7768cSFrancesco Fondelli } else { 16811ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 16821ca7768cSFrancesco Fondelli } 16831ca7768cSFrancesco Fondelli return count; 16841ca7768cSFrancesco Fondelli } 16851ca7768cSFrancesco Fondelli 16869e50e3acSJohn Fastabend if (!strcmp(name, "skb_priority")) { 16879e50e3acSJohn Fastabend len = num_arg(&user_buffer[i], 9, &value); 16889e50e3acSJohn Fastabend if (len < 0) 16899e50e3acSJohn Fastabend return len; 16909e50e3acSJohn Fastabend 16919e50e3acSJohn Fastabend i += len; 16929e50e3acSJohn Fastabend pkt_dev->skb_priority = value; 16939e50e3acSJohn Fastabend sprintf(pg_result, "OK: skb_priority=%i", 16949e50e3acSJohn Fastabend pkt_dev->skb_priority); 16959e50e3acSJohn Fastabend return count; 16969e50e3acSJohn Fastabend } 16979e50e3acSJohn Fastabend 16981da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 16991da177e4SLinus Torvalds return -EINVAL; 17001da177e4SLinus Torvalds } 17011da177e4SLinus Torvalds 1702d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17031da177e4SLinus Torvalds { 1704d9dda78bSAl Viro return single_open(file, pktgen_if_show, PDE_DATA(inode)); 17051da177e4SLinus Torvalds } 17061da177e4SLinus Torvalds 170797a32539SAlexey Dobriyan static const struct proc_ops pktgen_if_proc_ops = { 170897a32539SAlexey Dobriyan .proc_open = pktgen_if_open, 170997a32539SAlexey Dobriyan .proc_read = seq_read, 171097a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 171197a32539SAlexey Dobriyan .proc_write = pktgen_if_write, 171297a32539SAlexey Dobriyan .proc_release = single_release, 1713d50a6b56SStephen Hemminger }; 1714d50a6b56SStephen Hemminger 1715d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1716d50a6b56SStephen Hemminger { 1717d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1718648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1719d50a6b56SStephen Hemminger 1720d50a6b56SStephen Hemminger BUG_ON(!t); 1721d50a6b56SStephen Hemminger 172297dc48e2SThomas Graf seq_puts(seq, "Running: "); 17231da177e4SLinus Torvalds 17248788370aSJesper Dangaard Brouer rcu_read_lock(); 17258788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 17261da177e4SLinus Torvalds if (pkt_dev->running) 1727593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17281da177e4SLinus Torvalds 172997dc48e2SThomas Graf seq_puts(seq, "\nStopped: "); 17301da177e4SLinus Torvalds 17318788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 17321da177e4SLinus Torvalds if (!pkt_dev->running) 1733593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17341da177e4SLinus Torvalds 17351da177e4SLinus Torvalds if (t->result[0]) 1736d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17371da177e4SLinus Torvalds else 173897dc48e2SThomas Graf seq_puts(seq, "\nResult: NA\n"); 17391da177e4SLinus Torvalds 17408788370aSJesper Dangaard Brouer rcu_read_unlock(); 17411da177e4SLinus Torvalds 1742d50a6b56SStephen Hemminger return 0; 17431da177e4SLinus Torvalds } 17441da177e4SLinus Torvalds 1745d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1746d50a6b56SStephen Hemminger const char __user * user_buffer, 1747d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17481da177e4SLinus Torvalds { 17498a994a71SJoe Perches struct seq_file *seq = file->private_data; 1750d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1751d6182223SPaul Gortmaker int i, max, len, ret; 17521da177e4SLinus Torvalds char name[40]; 17531da177e4SLinus Torvalds char *pg_result; 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds if (count < 1) { 17561da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17571da177e4SLinus Torvalds return -EINVAL; 17581da177e4SLinus Torvalds } 17591da177e4SLinus Torvalds 1760d6182223SPaul Gortmaker max = count; 1761d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 17621da177e4SLinus Torvalds if (len < 0) 17631da177e4SLinus Torvalds return len; 17641da177e4SLinus Torvalds 1765d6182223SPaul Gortmaker i = len; 17661da177e4SLinus Torvalds 17671da177e4SLinus Torvalds /* Read variable name */ 17681da177e4SLinus Torvalds 17691da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 17701da177e4SLinus Torvalds if (len < 0) 17711da177e4SLinus Torvalds return len; 17721da177e4SLinus Torvalds 17731da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 17741da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 17751da177e4SLinus Torvalds return -EFAULT; 17761da177e4SLinus Torvalds i += len; 17771da177e4SLinus Torvalds 17781da177e4SLinus Torvalds max = count - i; 17791da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 17801da177e4SLinus Torvalds if (len < 0) 17811da177e4SLinus Torvalds return len; 17821da177e4SLinus Torvalds 17831da177e4SLinus Torvalds i += len; 17841da177e4SLinus Torvalds 17851da177e4SLinus Torvalds if (debug) 1786f342cda7SJoe Perches pr_debug("t=%s, count=%lu\n", name, (unsigned long)count); 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds if (!t) { 1789f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 17901da177e4SLinus Torvalds ret = -EINVAL; 17911da177e4SLinus Torvalds goto out; 17921da177e4SLinus Torvalds } 17931da177e4SLinus Torvalds 17941da177e4SLinus Torvalds pg_result = &(t->result[0]); 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 17971da177e4SLinus Torvalds char f[32]; 17981da177e4SLinus Torvalds memset(f, 0, 32); 17991da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18001da177e4SLinus Torvalds if (len < 0) { 18011da177e4SLinus Torvalds ret = len; 18021da177e4SLinus Torvalds goto out; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18051da177e4SLinus Torvalds return -EFAULT; 18061da177e4SLinus Torvalds i += len; 18076146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1808604dfd6eSCong Wang ret = pktgen_add_device(t, f); 18096146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1810604dfd6eSCong Wang if (!ret) { 18111da177e4SLinus Torvalds ret = count; 18121da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 1813604dfd6eSCong Wang } else 1814604dfd6eSCong Wang sprintf(pg_result, "ERROR: can not add device %s", f); 18151da177e4SLinus Torvalds goto out; 18161da177e4SLinus Torvalds } 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18196146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 182095ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18216146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1822121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18231da177e4SLinus Torvalds ret = count; 18241da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18251da177e4SLinus Torvalds goto out; 18261da177e4SLinus Torvalds } 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1829b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18301da177e4SLinus Torvalds ret = count; 18311da177e4SLinus Torvalds goto out; 18321da177e4SLinus Torvalds } 18331da177e4SLinus Torvalds 18341da177e4SLinus Torvalds ret = -EINVAL; 18351da177e4SLinus Torvalds out: 18361da177e4SLinus Torvalds return ret; 18371da177e4SLinus Torvalds } 18381da177e4SLinus Torvalds 1839d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18401da177e4SLinus Torvalds { 1841d9dda78bSAl Viro return single_open(file, pktgen_thread_show, PDE_DATA(inode)); 18421da177e4SLinus Torvalds } 18431da177e4SLinus Torvalds 184497a32539SAlexey Dobriyan static const struct proc_ops pktgen_thread_proc_ops = { 184597a32539SAlexey Dobriyan .proc_open = pktgen_thread_open, 184697a32539SAlexey Dobriyan .proc_read = seq_read, 184797a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 184897a32539SAlexey Dobriyan .proc_write = pktgen_thread_write, 184997a32539SAlexey Dobriyan .proc_release = single_release, 1850d50a6b56SStephen Hemminger }; 18511da177e4SLinus Torvalds 18521da177e4SLinus Torvalds /* Think find or remove for NN */ 18534e58a027SCong Wang static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, 18544e58a027SCong Wang const char *ifname, int remove) 18551da177e4SLinus Torvalds { 18561da177e4SLinus Torvalds struct pktgen_thread *t; 18571da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18583e984840SEric Dumazet bool exact = (remove == FIND); 18591da177e4SLinus Torvalds 18604e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 18613e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 18621da177e4SLinus Torvalds if (pkt_dev) { 18631da177e4SLinus Torvalds if (remove) { 186495ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 186595ed63f7SArthur Kepner t->control |= T_REMDEV; 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds break; 18681da177e4SLinus Torvalds } 18691da177e4SLinus Torvalds } 18701da177e4SLinus Torvalds return pkt_dev; 18711da177e4SLinus Torvalds } 18721da177e4SLinus Torvalds 187395ed63f7SArthur Kepner /* 187495ed63f7SArthur Kepner * mark a device for removal 187595ed63f7SArthur Kepner */ 18764e58a027SCong Wang static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname) 18771da177e4SLinus Torvalds { 18781da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 187995ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 188095ed63f7SArthur Kepner int i = 0; 188195ed63f7SArthur Kepner 18826146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1883f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 188495ed63f7SArthur Kepner 188595ed63f7SArthur Kepner while (1) { 188695ed63f7SArthur Kepner 18874e58a027SCong Wang pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE); 1888222f1806SLuiz Capitulino if (pkt_dev == NULL) 1889222f1806SLuiz Capitulino break; /* success */ 189095ed63f7SArthur Kepner 18916146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1892f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 1893f9467eaeSJoe Perches __func__, ifname); 189495ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 18956146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 189695ed63f7SArthur Kepner 189795ed63f7SArthur Kepner if (++i >= max_tries) { 1898f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 1899f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 190095ed63f7SArthur Kepner break; 190195ed63f7SArthur Kepner } 190295ed63f7SArthur Kepner 190395ed63f7SArthur Kepner } 190495ed63f7SArthur Kepner 19056146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 190639df232fSStephen Hemminger } 190795ed63f7SArthur Kepner 19084e58a027SCong Wang static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) 190939df232fSStephen Hemminger { 191039df232fSStephen Hemminger struct pktgen_thread *t; 191139df232fSStephen Hemminger 19129a0b1e8bSEric Dumazet mutex_lock(&pktgen_thread_lock); 19139a0b1e8bSEric Dumazet 19144e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 191539df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 191639df232fSStephen Hemminger 19179a0b1e8bSEric Dumazet if_lock(t); 19189a0b1e8bSEric Dumazet list_for_each_entry(pkt_dev, &t->if_list, list) { 191939df232fSStephen Hemminger if (pkt_dev->odev != dev) 192039df232fSStephen Hemminger continue; 192139df232fSStephen Hemminger 1922a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 192339df232fSStephen Hemminger 19242975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 19254e58a027SCong Wang pn->proc_dir, 192697a32539SAlexey Dobriyan &pktgen_if_proc_ops, 19272975315bSAlexey Dobriyan pkt_dev); 192839df232fSStephen Hemminger if (!pkt_dev->entry) 1929f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 1930f9467eaeSJoe Perches dev->name); 193139df232fSStephen Hemminger break; 193239df232fSStephen Hemminger } 19339a0b1e8bSEric Dumazet if_unlock(t); 193439df232fSStephen Hemminger } 19359a0b1e8bSEric Dumazet mutex_unlock(&pktgen_thread_lock); 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 1938222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1939222f1806SLuiz Capitulino unsigned long event, void *ptr) 19401da177e4SLinus Torvalds { 1941351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 19424e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id); 19431da177e4SLinus Torvalds 19444e58a027SCong Wang if (pn->pktgen_exiting) 1945e9dc8653SEric W. Biederman return NOTIFY_DONE; 1946e9dc8653SEric W. Biederman 19471da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19481da177e4SLinus Torvalds * as we run under the RTNL lock. 19491da177e4SLinus Torvalds */ 19501da177e4SLinus Torvalds 19511da177e4SLinus Torvalds switch (event) { 195239df232fSStephen Hemminger case NETDEV_CHANGENAME: 19534e58a027SCong Wang pktgen_change_name(pn, dev); 19541da177e4SLinus Torvalds break; 19551da177e4SLinus Torvalds 19561da177e4SLinus Torvalds case NETDEV_UNREGISTER: 19574e58a027SCong Wang pktgen_mark_device(pn, dev->name); 19581da177e4SLinus Torvalds break; 19593ff50b79SStephen Hemminger } 19601da177e4SLinus Torvalds 19611da177e4SLinus Torvalds return NOTIFY_DONE; 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds 19644e58a027SCong Wang static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn, 19654e58a027SCong Wang struct pktgen_dev *pkt_dev, 196663adc6fbSStephen Hemminger const char *ifname) 1967e6fce5b9SRobert Olsson { 1968e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 1969d6182223SPaul Gortmaker int i; 1970e6fce5b9SRobert Olsson 1971e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 1972e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 1973e6fce5b9SRobert Olsson break; 1974e6fce5b9SRobert Olsson 1975e6fce5b9SRobert Olsson b[i] = ifname[i]; 1976e6fce5b9SRobert Olsson } 1977e6fce5b9SRobert Olsson b[i] = 0; 1978e6fce5b9SRobert Olsson 19794e58a027SCong Wang return dev_get_by_name(pn->net, b); 1980e6fce5b9SRobert Olsson } 1981e6fce5b9SRobert Olsson 1982e6fce5b9SRobert Olsson 19831da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 19841da177e4SLinus Torvalds 19854e58a027SCong Wang static int pktgen_setup_dev(const struct pktgen_net *pn, 19864e58a027SCong Wang struct pktgen_dev *pkt_dev, const char *ifname) 1987222f1806SLuiz Capitulino { 19881da177e4SLinus Torvalds struct net_device *odev; 198939df232fSStephen Hemminger int err; 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds /* Clean old setups */ 19921da177e4SLinus Torvalds if (pkt_dev->odev) { 19931da177e4SLinus Torvalds dev_put(pkt_dev->odev); 19941da177e4SLinus Torvalds pkt_dev->odev = NULL; 19951da177e4SLinus Torvalds } 19961da177e4SLinus Torvalds 19974e58a027SCong Wang odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname); 19981da177e4SLinus Torvalds if (!odev) { 1999f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 200039df232fSStephen Hemminger return -ENODEV; 20011da177e4SLinus Torvalds } 200239df232fSStephen Hemminger 20031e09e581SLukas Wunner if (odev->type != ARPHRD_ETHER && odev->type != ARPHRD_LOOPBACK) { 20041e09e581SLukas Wunner pr_err("not an ethernet or loopback device: \"%s\"\n", ifname); 200539df232fSStephen Hemminger err = -EINVAL; 200639df232fSStephen Hemminger } else if (!netif_running(odev)) { 2007f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 200839df232fSStephen Hemminger err = -ENETDOWN; 200939df232fSStephen Hemminger } else { 20101da177e4SLinus Torvalds pkt_dev->odev = odev; 201139df232fSStephen Hemminger return 0; 201239df232fSStephen Hemminger } 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds dev_put(odev); 201539df232fSStephen Hemminger return err; 20161da177e4SLinus Torvalds } 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 20191da177e4SLinus Torvalds * structure to have the right information to create/send packets 20201da177e4SLinus Torvalds */ 20211da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20221da177e4SLinus Torvalds { 202364c00d81SAndrew Gallatin int ntxq; 202464c00d81SAndrew Gallatin 20251da177e4SLinus Torvalds if (!pkt_dev->odev) { 2026f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2027222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2028222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20291da177e4SLinus Torvalds return; 20301da177e4SLinus Torvalds } 20311da177e4SLinus Torvalds 203264c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 203364c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2034bfdbc0acSRobert Olsson 203564c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2036294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 203788271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2038593f63b0SEric Dumazet pkt_dev->odevname); 203926e29eedSDan Carpenter pkt_dev->queue_map_min = (ntxq ?: 1) - 1; 204064c00d81SAndrew Gallatin } 204188271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2042294a0b7fSJoe Perches pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 204388271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2044593f63b0SEric Dumazet pkt_dev->odevname); 204526e29eedSDan Carpenter pkt_dev->queue_map_max = (ntxq ?: 1) - 1; 204664c00d81SAndrew Gallatin } 204764c00d81SAndrew Gallatin 20481da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20491da177e4SLinus Torvalds 2050f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 20519ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds /* Set up Dest MAC */ 20549ea08b12SJoe Perches ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20574c139b8cSAmerigo Wang int i, set = 0, err = 1; 20584c139b8cSAmerigo Wang struct inet6_dev *idev; 20594c139b8cSAmerigo Wang 206068bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 206168bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr) 206268bf9f0bSAmerigo Wang + sizeof(struct udphdr) 206368bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 206468bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 206568bf9f0bSAmerigo Wang } 206668bf9f0bSAmerigo Wang 2067df7e8e2eSEric Dumazet for (i = 0; i < sizeof(struct in6_addr); i++) 20681da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20691da177e4SLinus Torvalds set = 1; 20701da177e4SLinus Torvalds break; 20711da177e4SLinus Torvalds } 20721da177e4SLinus Torvalds 20731da177e4SLinus Torvalds if (!set) { 20741da177e4SLinus Torvalds 20751da177e4SLinus Torvalds /* 20761da177e4SLinus Torvalds * Use linklevel address if unconfigured. 20771da177e4SLinus Torvalds * 20781da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 20791da177e4SLinus Torvalds */ 20801da177e4SLinus Torvalds 20818814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 208263adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 208363adc6fbSStephen Hemminger if (idev) { 20841da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds read_lock_bh(&idev->lock); 20874c139b8cSAmerigo Wang list_for_each_entry(ifp, &idev->addr_list, if_list) { 20884c139b8cSAmerigo Wang if ((ifp->scope & IFA_LINK) && 2089f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 20904e3fd7a0SAlexey Dobriyan pkt_dev->cur_in6_saddr = ifp->addr; 20911da177e4SLinus Torvalds err = 0; 20921da177e4SLinus Torvalds break; 20931da177e4SLinus Torvalds } 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 20961da177e4SLinus Torvalds } 20978814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2098222f1806SLuiz Capitulino if (err) 2099f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 21001da177e4SLinus Torvalds } 2101222f1806SLuiz Capitulino } else { 210268bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size == 0) { 210368bf9f0bSAmerigo Wang pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr) 210468bf9f0bSAmerigo Wang + sizeof(struct udphdr) 210568bf9f0bSAmerigo Wang + sizeof(struct pktgen_hdr) 210668bf9f0bSAmerigo Wang + pkt_dev->pkt_overhead; 210768bf9f0bSAmerigo Wang } 210868bf9f0bSAmerigo Wang 21091da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 21101da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 21111da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 21121da177e4SLinus Torvalds 21131da177e4SLinus Torvalds struct in_device *in_dev; 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds rcu_read_lock(); 2116e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 21171da177e4SLinus Torvalds if (in_dev) { 21182638eb8bSFlorian Westphal const struct in_ifaddr *ifa; 21192638eb8bSFlorian Westphal 21202638eb8bSFlorian Westphal ifa = rcu_dereference(in_dev->ifa_list); 21212638eb8bSFlorian Westphal if (ifa) { 21222638eb8bSFlorian Westphal pkt_dev->saddr_min = ifa->ifa_address; 21231da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds } 21261da177e4SLinus Torvalds rcu_read_unlock(); 2127222f1806SLuiz Capitulino } else { 21281da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21291da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21301da177e4SLinus Torvalds } 21311da177e4SLinus Torvalds 21321da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21331da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21341da177e4SLinus Torvalds } 21351da177e4SLinus Torvalds /* Initialize current values. */ 213668bf9f0bSAmerigo Wang pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 213768bf9f0bSAmerigo Wang if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size) 213868bf9f0bSAmerigo Wang pkt_dev->max_pkt_size = pkt_dev->min_pkt_size; 213968bf9f0bSAmerigo Wang 21401da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 21411da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 21421da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 21431da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 21441da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21451da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21461da177e4SLinus Torvalds pkt_dev->nflows = 0; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds 21491da177e4SLinus Torvalds 2150fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2151fd29cf72SStephen Hemminger { 2152ef87979cSStephen Hemminger ktime_t start_time, end_time; 2153417bc4b8SEric Dumazet s64 remaining; 21542bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2155fd29cf72SStephen Hemminger 2156dbc1625fSSebastian Andrzej Siewior hrtimer_init_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21572bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2158fd29cf72SStephen Hemminger 215943d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2160bcf91bdbSGuenter Roeck if (remaining <= 0) 2161bcf91bdbSGuenter Roeck goto out; 21622bc481cfSStephen Hemminger 2163398f382cSDaniel Borkmann start_time = ktime_get(); 216433136d12SEric Dumazet if (remaining < 100000) { 216533136d12SEric Dumazet /* for small delays (<100us), just loop until limit is reached */ 216633136d12SEric Dumazet do { 2167398f382cSDaniel Borkmann end_time = ktime_get(); 2168398f382cSDaniel Borkmann } while (ktime_compare(end_time, spin_until) < 0); 216933136d12SEric Dumazet } else { 21702bc481cfSStephen Hemminger do { 21712bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 21729dd8813eSThomas Gleixner hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_ABS); 21732bc481cfSStephen Hemminger 21742bc481cfSStephen Hemminger if (likely(t.task)) 21751da177e4SLinus Torvalds schedule(); 21761da177e4SLinus Torvalds 21772bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 21782bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 21792bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 2180398f382cSDaniel Borkmann end_time = ktime_get(); 218133136d12SEric Dumazet } 2182ef87979cSStephen Hemminger 2183ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 2184bcf91bdbSGuenter Roeck out: 218507a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 2186bcf91bdbSGuenter Roeck destroy_hrtimer_on_stack(&t.timer); 21871da177e4SLinus Torvalds } 21881da177e4SLinus Torvalds 218916dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 219016dab72fSJamal Hadi Salim { 219163d75463SPaolo Abeni pkt_dev->pkt_overhead = 0; 219216dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 219316dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 219416dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 219516dab72fSJamal Hadi Salim } 219616dab72fSJamal Hadi Salim 2197648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2198007a531bSJamal Hadi Salim { 2199648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2200007a531bSJamal Hadi Salim } 2201007a531bSJamal Hadi Salim 2202007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2203007a531bSJamal Hadi Salim { 2204007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2205007a531bSJamal Hadi Salim 2206007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2207007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2208007a531bSJamal Hadi Salim /* reset time */ 2209007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22101211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2211007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2212007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2213007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2214007a531bSJamal Hadi Salim } 2215007a531bSJamal Hadi Salim } else { 221633d7c5e5SAkinobu Mita flow = prandom_u32() % pkt_dev->cflows; 22171211a645SRobert Olsson pkt_dev->curfl = flow; 2218007a531bSJamal Hadi Salim 22191211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2220007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22211211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 22221211a645SRobert Olsson } 2223007a531bSJamal Hadi Salim } 2224007a531bSJamal Hadi Salim 2225007a531bSJamal Hadi Salim return pkt_dev->curfl; 2226007a531bSJamal Hadi Salim } 2227007a531bSJamal Hadi Salim 2228a553e4a6SJamal Hadi Salim 2229a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2230a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2231a553e4a6SJamal Hadi Salim * we go look for it ... 2232a553e4a6SJamal Hadi Salim */ 2233bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2234fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2235a553e4a6SJamal Hadi Salim { 2236a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 22374e58a027SCong Wang struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); 2238a553e4a6SJamal Hadi Salim if (!x) { 2239c454997eSFan Du 2240c454997eSFan Du if (pkt_dev->spi) { 2241c454997eSFan Du /* We need as quick as possible to find the right SA 2242c454997eSFan Du * Searching with minimum criteria to archieve this. 2243c454997eSFan Du */ 2244c454997eSFan Du x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); 2245c454997eSFan Du } else { 2246a553e4a6SJamal Hadi Salim /* slow path: we dont already have xfrm_state */ 22477e652640SSteffen Klassert x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0, 22485447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2249a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2250a553e4a6SJamal Hadi Salim AF_INET, 2251a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2252a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2253c454997eSFan Du } 2254a553e4a6SJamal Hadi Salim if (x) { 2255a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2256a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2257a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2258a553e4a6SJamal Hadi Salim } 2259a553e4a6SJamal Hadi Salim 2260a553e4a6SJamal Hadi Salim } 2261a553e4a6SJamal Hadi Salim } 2262a553e4a6SJamal Hadi Salim #endif 2263fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2264fd2ea0a7SDavid S. Miller { 2265e6fce5b9SRobert Olsson 2266e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2267e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2268e6fce5b9SRobert Olsson 2269896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2270fd2ea0a7SDavid S. Miller __u16 t; 2271fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 227233d7c5e5SAkinobu Mita t = prandom_u32() % 2273fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2274fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2275fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2276fd2ea0a7SDavid S. Miller } else { 2277fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2278fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2279fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2280fd2ea0a7SDavid S. Miller } 2281fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2282fd2ea0a7SDavid S. Miller } 2283bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2284fd2ea0a7SDavid S. Miller } 2285fd2ea0a7SDavid S. Miller 22861da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 22871da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 22881da177e4SLinus Torvalds */ 2289222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2290222f1806SLuiz Capitulino { 22911da177e4SLinus Torvalds __u32 imn; 22921da177e4SLinus Torvalds __u32 imx; 22931da177e4SLinus Torvalds int flow = 0; 22941da177e4SLinus Torvalds 2295007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2296007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 22971da177e4SLinus Torvalds 22981da177e4SLinus Torvalds /* Deal with source MAC */ 22991da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 23001da177e4SLinus Torvalds __u32 mc; 23011da177e4SLinus Torvalds __u32 tmp; 23021da177e4SLinus Torvalds 23031da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 230433d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->src_mac_count; 23051da177e4SLinus Torvalds else { 23061da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2307ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2308222f1806SLuiz Capitulino pkt_dev->src_mac_count) 23091da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 23101da177e4SLinus Torvalds } 23111da177e4SLinus Torvalds 23121da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23131da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 23141da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23151da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 23161da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23171da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 23181da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23191da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 23201da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23211da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 23221da177e4SLinus Torvalds } 23231da177e4SLinus Torvalds 23241da177e4SLinus Torvalds /* Deal with Destination MAC */ 23251da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 23261da177e4SLinus Torvalds __u32 mc; 23271da177e4SLinus Torvalds __u32 tmp; 23281da177e4SLinus Torvalds 23291da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 233033d7c5e5SAkinobu Mita mc = prandom_u32() % pkt_dev->dst_mac_count; 23311da177e4SLinus Torvalds 23321da177e4SLinus Torvalds else { 23331da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2334ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2335222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 23361da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 23371da177e4SLinus Torvalds } 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds 23401da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23411da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 23421da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23431da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 23441da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23451da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 23461da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23471da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 23481da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23491da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 23501da177e4SLinus Torvalds } 23511da177e4SLinus Torvalds 2352ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 235395c96174SEric Dumazet unsigned int i; 2354ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2355ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2356ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 235733d7c5e5SAkinobu Mita ((__force __be32)prandom_u32() & 2358ca6549afSSteven Whitehouse htonl(0x000fffff)); 2359ca6549afSSteven Whitehouse } 2360ca6549afSSteven Whitehouse 236134954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 236233d7c5e5SAkinobu Mita pkt_dev->vlan_id = prandom_u32() & (4096 - 1); 236334954ddcSFrancesco Fondelli } 236434954ddcSFrancesco Fondelli 236534954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 236633d7c5e5SAkinobu Mita pkt_dev->svlan_id = prandom_u32() & (4096 - 1); 236734954ddcSFrancesco Fondelli } 236834954ddcSFrancesco Fondelli 23691da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23701da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 237133d7c5e5SAkinobu Mita pkt_dev->cur_udp_src = prandom_u32() % 23725fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23735fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds else { 23761da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 23771da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 23781da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 23791da177e4SLinus Torvalds } 23801da177e4SLinus Torvalds } 23811da177e4SLinus Torvalds 23821da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 23831da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 238433d7c5e5SAkinobu Mita pkt_dev->cur_udp_dst = prandom_u32() % 23855fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 23865fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2387222f1806SLuiz Capitulino } else { 23881da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 23891da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 23901da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds } 23931da177e4SLinus Torvalds 23941da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 23951da177e4SLinus Torvalds 239663adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 239763adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 239863adc6fbSStephen Hemminger if (imn < imx) { 23991da177e4SLinus Torvalds __u32 t; 24001da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 240133d7c5e5SAkinobu Mita t = prandom_u32() % (imx - imn) + imn; 24021da177e4SLinus Torvalds else { 24031da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 24041da177e4SLinus Torvalds t++; 240563adc6fbSStephen Hemminger if (t > imx) 24061da177e4SLinus Torvalds t = imn; 240763adc6fbSStephen Hemminger 24081da177e4SLinus Torvalds } 24091da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 24101da177e4SLinus Torvalds } 24111da177e4SLinus Torvalds 2412007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24131da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24141da177e4SLinus Torvalds } else { 2415252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2416252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2417252e3346SAl Viro if (imn < imx) { 24181da177e4SLinus Torvalds __u32 t; 2419252e3346SAl Viro __be32 s; 24201da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 24211da177e4SLinus Torvalds 242270e3ba72SAkinobu Mita do { 242333d7c5e5SAkinobu Mita t = prandom_u32() % 242433d7c5e5SAkinobu Mita (imx - imn) + imn; 2425252e3346SAl Viro s = htonl(t); 242670e3ba72SAkinobu Mita } while (ipv4_is_loopback(s) || 242770e3ba72SAkinobu Mita ipv4_is_multicast(s) || 242870e3ba72SAkinobu Mita ipv4_is_lbcast(s) || 242970e3ba72SAkinobu Mita ipv4_is_zeronet(s) || 243070e3ba72SAkinobu Mita ipv4_is_local_multicast(s)); 2431252e3346SAl Viro pkt_dev->cur_daddr = s; 2432252e3346SAl Viro } else { 24331da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 24341da177e4SLinus Torvalds t++; 24351da177e4SLinus Torvalds if (t > imx) { 24361da177e4SLinus Torvalds t = imn; 24371da177e4SLinus Torvalds } 24381da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 24391da177e4SLinus Torvalds } 24401da177e4SLinus Torvalds } 24411da177e4SLinus Torvalds if (pkt_dev->cflows) { 2442007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2443222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2444222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2445a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 24466f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) 2447a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2448a553e4a6SJamal Hadi Salim #endif 24491da177e4SLinus Torvalds pkt_dev->nflows++; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds } 2452222f1806SLuiz Capitulino } else { /* IPV6 * */ 2453222f1806SLuiz Capitulino 245406e30411SJoe Perches if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) { 24551da177e4SLinus Torvalds int i; 24561da177e4SLinus Torvalds 24571da177e4SLinus Torvalds /* Only random destinations yet */ 24581da177e4SLinus Torvalds 24591da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 24601da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 246133d7c5e5SAkinobu Mita (((__force __be32)prandom_u32() | 24621da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 24631da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 24641da177e4SLinus Torvalds } 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds } 24671da177e4SLinus Torvalds 24681da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24691da177e4SLinus Torvalds __u32 t; 24701da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 247133d7c5e5SAkinobu Mita t = prandom_u32() % 24725fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24735fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2474222f1806SLuiz Capitulino } else { 24751da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 24761da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 24771da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 24781da177e4SLinus Torvalds } 24791da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 24801da177e4SLinus Torvalds } 24811da177e4SLinus Torvalds 2482fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 248345b270f8SRobert Olsson 24841da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds 2487a553e4a6SJamal Hadi Salim 2488a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 24895537a055SFengguang Wu static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { 2490cf93d47eSFan Du 2491cf93d47eSFan Du [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ 2492cf93d47eSFan Du }; 2493cf93d47eSFan Du 2494a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2495a553e4a6SJamal Hadi Salim { 2496a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2497a553e4a6SJamal Hadi Salim int err = 0; 24986de9ace4SFan Du struct net *net = dev_net(pkt_dev->odev); 2499a553e4a6SJamal Hadi Salim 2500a553e4a6SJamal Hadi Salim if (!x) 2501a553e4a6SJamal Hadi Salim return 0; 2502a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2503a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2504cf93d47eSFan Du if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) 2505a553e4a6SJamal Hadi Salim return 0; 2506a553e4a6SJamal Hadi Salim 2507cf93d47eSFan Du /* But when user specify an valid SPI, transformation 2508cf93d47eSFan Du * supports both transport/tunnel mode + ESP/AH type. 2509cf93d47eSFan Du */ 2510cf93d47eSFan Du if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) 2511b6ca8bd5SDavid Miller skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF; 2512cf93d47eSFan Du 2513cf93d47eSFan Du rcu_read_lock_bh(); 25140c620e97SFlorian Westphal err = pktgen_xfrm_outer_mode_output(x, skb); 2515cf93d47eSFan Du rcu_read_unlock_bh(); 25166de9ace4SFan Du if (err) { 25176de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); 2518a553e4a6SJamal Hadi Salim goto error; 25196de9ace4SFan Du } 2520a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 25216de9ace4SFan Du if (err) { 25226de9ace4SFan Du XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); 2523a553e4a6SJamal Hadi Salim goto error; 25246de9ace4SFan Du } 25250af0a413SFan Du spin_lock_bh(&x->lock); 2526a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2527a553e4a6SJamal Hadi Salim x->curlft.packets++; 25280af0a413SFan Du spin_unlock_bh(&x->lock); 2529a553e4a6SJamal Hadi Salim error: 2530a553e4a6SJamal Hadi Salim return err; 2531a553e4a6SJamal Hadi Salim } 2532a553e4a6SJamal Hadi Salim 2533475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2534a553e4a6SJamal Hadi Salim { 2535a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2536a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2537d6182223SPaul Gortmaker int i; 2538d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2539a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2540a553e4a6SJamal Hadi Salim if (x) { 2541a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2542a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2543a553e4a6SJamal Hadi Salim } 2544a553e4a6SJamal Hadi Salim } 2545a553e4a6SJamal Hadi Salim } 2546a553e4a6SJamal Hadi Salim } 2547a553e4a6SJamal Hadi Salim 2548475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2549a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2550a553e4a6SJamal Hadi Salim { 25516f107c74SDmitry Safonov if (pkt_dev->flags & F_IPSEC) { 2552a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2553a553e4a6SJamal Hadi Salim int nhead = 0; 2554a553e4a6SJamal Hadi Salim if (x) { 2555d4969581SEric Dumazet struct ethhdr *eth; 25563868204dSfan.du struct iphdr *iph; 2557d4969581SEric Dumazet int ret; 25583868204dSfan.du 2559a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2560a553e4a6SJamal Hadi Salim if (nhead > 0) { 2561a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2562a553e4a6SJamal Hadi Salim if (ret < 0) { 2563f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2564f9467eaeSJoe Perches ret); 2565b4bb4ac8SIlpo Järvinen goto err; 2566a553e4a6SJamal Hadi Salim } 2567a553e4a6SJamal Hadi Salim } 2568a553e4a6SJamal Hadi Salim 2569a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2570a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2571a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2572a553e4a6SJamal Hadi Salim if (ret) { 2573f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2574b4bb4ac8SIlpo Järvinen goto err; 2575a553e4a6SJamal Hadi Salim } 2576a553e4a6SJamal Hadi Salim /* restore ll */ 2577d58ff351SJohannes Berg eth = skb_push(skb, ETH_HLEN); 2578d4969581SEric Dumazet memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN); 2579d4969581SEric Dumazet eth->h_proto = protocol; 25803868204dSfan.du 25813868204dSfan.du /* Update IPv4 header len as well as checksum value */ 25823868204dSfan.du iph = ip_hdr(skb); 25833868204dSfan.du iph->tot_len = htons(skb->len - ETH_HLEN); 25843868204dSfan.du ip_send_check(iph); 2585a553e4a6SJamal Hadi Salim } 2586a553e4a6SJamal Hadi Salim } 2587a553e4a6SJamal Hadi Salim return 1; 2588b4bb4ac8SIlpo Järvinen err: 2589b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2590b4bb4ac8SIlpo Järvinen return 0; 2591a553e4a6SJamal Hadi Salim } 2592a553e4a6SJamal Hadi Salim #endif 2593a553e4a6SJamal Hadi Salim 2594ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2595ca6549afSSteven Whitehouse { 259695c96174SEric Dumazet unsigned int i; 259763adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2598ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 259963adc6fbSStephen Hemminger 2600ca6549afSSteven Whitehouse mpls--; 2601ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2602ca6549afSSteven Whitehouse } 2603ca6549afSSteven Whitehouse 26040f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 26050f37c605SAl Viro unsigned int prio) 26060f37c605SAl Viro { 26070f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 26080f37c605SAl Viro } 26090f37c605SAl Viro 261026ad7879SEric Dumazet static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, 261126ad7879SEric Dumazet int datalen) 261226ad7879SEric Dumazet { 26137f5d3f27SArnd Bergmann struct timespec64 timestamp; 261426ad7879SEric Dumazet struct pktgen_hdr *pgh; 261526ad7879SEric Dumazet 26164df864c1SJohannes Berg pgh = skb_put(skb, sizeof(*pgh)); 261726ad7879SEric Dumazet datalen -= sizeof(*pgh); 261826ad7879SEric Dumazet 261926ad7879SEric Dumazet if (pkt_dev->nfrags <= 0) { 2620b080db58SJohannes Berg skb_put_zero(skb, datalen); 262126ad7879SEric Dumazet } else { 262226ad7879SEric Dumazet int frags = pkt_dev->nfrags; 262326ad7879SEric Dumazet int i, len; 26247d36a991Samit salecha int frag_len; 262526ad7879SEric Dumazet 262626ad7879SEric Dumazet 262726ad7879SEric Dumazet if (frags > MAX_SKB_FRAGS) 262826ad7879SEric Dumazet frags = MAX_SKB_FRAGS; 262926ad7879SEric Dumazet len = datalen - frags * PAGE_SIZE; 263026ad7879SEric Dumazet if (len > 0) { 2631b080db58SJohannes Berg skb_put_zero(skb, len); 263226ad7879SEric Dumazet datalen = frags * PAGE_SIZE; 263326ad7879SEric Dumazet } 263426ad7879SEric Dumazet 263526ad7879SEric Dumazet i = 0; 26367d36a991Samit salecha frag_len = (datalen/frags) < PAGE_SIZE ? 26377d36a991Samit salecha (datalen/frags) : PAGE_SIZE; 263826ad7879SEric Dumazet while (datalen > 0) { 263926ad7879SEric Dumazet if (unlikely(!pkt_dev->page)) { 264026ad7879SEric Dumazet int node = numa_node_id(); 264126ad7879SEric Dumazet 264226ad7879SEric Dumazet if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE)) 264326ad7879SEric Dumazet node = pkt_dev->node; 264426ad7879SEric Dumazet pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); 264526ad7879SEric Dumazet if (!pkt_dev->page) 264626ad7879SEric Dumazet break; 264726ad7879SEric Dumazet } 2648a0bec1cdSIan Campbell get_page(pkt_dev->page); 2649ea2ab693SIan Campbell skb_frag_set_page(skb, i, pkt_dev->page); 2650b54c9d5bSJonathan Lemon skb_frag_off_set(&skb_shinfo(skb)->frags[i], 0); 26517d36a991Samit salecha /*last fragment, fill rest of data*/ 26527d36a991Samit salecha if (i == (frags - 1)) 26539e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], 26549e903e08SEric Dumazet (datalen < PAGE_SIZE ? datalen : PAGE_SIZE)); 26557d36a991Samit salecha else 26569e903e08SEric Dumazet skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len); 26579e903e08SEric Dumazet datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]); 26589e903e08SEric Dumazet skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 26599e903e08SEric Dumazet skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 266026ad7879SEric Dumazet i++; 266126ad7879SEric Dumazet skb_shinfo(skb)->nr_frags = i; 266226ad7879SEric Dumazet } 266326ad7879SEric Dumazet } 266426ad7879SEric Dumazet 266526ad7879SEric Dumazet /* Stamp the time, and sequence number, 266626ad7879SEric Dumazet * convert them to network byte order 266726ad7879SEric Dumazet */ 266826ad7879SEric Dumazet pgh->pgh_magic = htonl(PKTGEN_MAGIC); 266926ad7879SEric Dumazet pgh->seq_num = htonl(pkt_dev->seq_num); 267026ad7879SEric Dumazet 2671afb84b62SJesper Dangaard Brouer if (pkt_dev->flags & F_NO_TIMESTAMP) { 2672afb84b62SJesper Dangaard Brouer pgh->tv_sec = 0; 2673afb84b62SJesper Dangaard Brouer pgh->tv_usec = 0; 2674afb84b62SJesper Dangaard Brouer } else { 26757f5d3f27SArnd Bergmann /* 26767f5d3f27SArnd Bergmann * pgh->tv_sec wraps in y2106 when interpreted as unsigned 26777f5d3f27SArnd Bergmann * as done by wireshark, or y2038 when interpreted as signed. 26787f5d3f27SArnd Bergmann * This is probably harmless, but if anyone wants to improve 26797f5d3f27SArnd Bergmann * it, we could introduce a variant that puts 64-bit nanoseconds 26807f5d3f27SArnd Bergmann * into the respective header bytes. 26817f5d3f27SArnd Bergmann * This would also be slightly faster to read. 26827f5d3f27SArnd Bergmann */ 26837f5d3f27SArnd Bergmann ktime_get_real_ts64(×tamp); 268426ad7879SEric Dumazet pgh->tv_sec = htonl(timestamp.tv_sec); 26857f5d3f27SArnd Bergmann pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC); 268626ad7879SEric Dumazet } 2687afb84b62SJesper Dangaard Brouer } 268826ad7879SEric Dumazet 26897a6e288dSDaniel Borkmann static struct sk_buff *pktgen_alloc_skb(struct net_device *dev, 269063d75463SPaolo Abeni struct pktgen_dev *pkt_dev) 26917a6e288dSDaniel Borkmann { 269263d75463SPaolo Abeni unsigned int extralen = LL_RESERVED_SPACE(dev); 26937a6e288dSDaniel Borkmann struct sk_buff *skb = NULL; 269463d75463SPaolo Abeni unsigned int size; 26957a6e288dSDaniel Borkmann 269663d75463SPaolo Abeni size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead; 26977a6e288dSDaniel Borkmann if (pkt_dev->flags & F_NODE) { 26987a6e288dSDaniel Borkmann int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id(); 26997a6e288dSDaniel Borkmann 27007a6e288dSDaniel Borkmann skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node); 27017a6e288dSDaniel Borkmann if (likely(skb)) { 27027a6e288dSDaniel Borkmann skb_reserve(skb, NET_SKB_PAD); 27037a6e288dSDaniel Borkmann skb->dev = dev; 27047a6e288dSDaniel Borkmann } 27057a6e288dSDaniel Borkmann } else { 27067a6e288dSDaniel Borkmann skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT); 27077a6e288dSDaniel Borkmann } 27083de03596SJohn Fastabend 270963d75463SPaolo Abeni /* the caller pre-fetches from skb->data and reserves for the mac hdr */ 27103de03596SJohn Fastabend if (likely(skb)) 271163d75463SPaolo Abeni skb_reserve(skb, extralen - 16); 27127a6e288dSDaniel Borkmann 27137a6e288dSDaniel Borkmann return skb; 27147a6e288dSDaniel Borkmann } 27157a6e288dSDaniel Borkmann 27161da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 27171da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 27181da177e4SLinus Torvalds { 27191da177e4SLinus Torvalds struct sk_buff *skb = NULL; 27201da177e4SLinus Torvalds __u8 *eth; 27211da177e4SLinus Torvalds struct udphdr *udph; 27221da177e4SLinus Torvalds int datalen, iplen; 27231da177e4SLinus Torvalds struct iphdr *iph; 2724d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2725ca6549afSSteven Whitehouse __be32 *mpls; 272634954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 272734954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 272834954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 272934954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2730fd2ea0a7SDavid S. Miller u16 queue_map; 2731ca6549afSSteven Whitehouse 2732ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2733d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 27341da177e4SLinus Torvalds 273534954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2736d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 273734954ddcSFrancesco Fondelli 273864053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 273964053beeSRobert Olsson * fields. 274064053beeSRobert Olsson */ 274164053beeSRobert Olsson mod_cur_headers(pkt_dev); 2742eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 274364053beeSRobert Olsson 274463d75463SPaolo Abeni skb = pktgen_alloc_skb(odev, pkt_dev); 27451da177e4SLinus Torvalds if (!skb) { 27461da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 27471da177e4SLinus Torvalds return NULL; 27481da177e4SLinus Torvalds } 27491da177e4SLinus Torvalds 27507a6e288dSDaniel Borkmann prefetchw(skb->data); 275163d75463SPaolo Abeni skb_reserve(skb, 16); 27521da177e4SLinus Torvalds 27531da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 2754d58ff351SJohannes Berg eth = skb_push(skb, 14); 27554df864c1SJohannes Berg mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 2756ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2757ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 275834954ddcSFrancesco Fondelli 275934954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 276034954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 27614df864c1SJohannes Berg svlan_tci = skb_put(skb, sizeof(__be16)); 27620f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 27630f37c605SAl Viro pkt_dev->svlan_cfi, 27640f37c605SAl Viro pkt_dev->svlan_p); 27654df864c1SJohannes Berg svlan_encapsulated_proto = skb_put(skb, 27664df864c1SJohannes Berg sizeof(__be16)); 2767d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 276834954ddcSFrancesco Fondelli } 27694df864c1SJohannes Berg vlan_tci = skb_put(skb, sizeof(__be16)); 27700f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 27710f37c605SAl Viro pkt_dev->vlan_cfi, 27720f37c605SAl Viro pkt_dev->vlan_p); 27734df864c1SJohannes Berg vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 2774d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 277534954ddcSFrancesco Fondelli } 277634954ddcSFrancesco Fondelli 2777c145aeb3SZhang Shengju skb_reset_mac_header(skb); 2778525cebedSThomas Graf skb_set_network_header(skb, skb->len); 27794df864c1SJohannes Berg iph = skb_put(skb, sizeof(struct iphdr)); 2780525cebedSThomas Graf 2781525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 27824df864c1SJohannes Berg udph = skb_put(skb, sizeof(struct udphdr)); 2783fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 27849e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 27859e50e3acSJohn Fastabend 27861da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2787252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 27881da177e4SLinus Torvalds 2789ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2790ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 279116dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 27926af773e7SNishank Trivedi if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) 27931da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 27941da177e4SLinus Torvalds 27951da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 27961da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 27971da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 2798c26bf4a5SThomas Graf udph->check = 0; 27991da177e4SLinus Torvalds 28001da177e4SLinus Torvalds iph->ihl = 5; 28011da177e4SLinus Torvalds iph->version = 4; 28021da177e4SLinus Torvalds iph->ttl = 32; 28031ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 28041da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 28051da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 28061da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 280766ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 280866ed1e5eSEric Dumazet pkt_dev->ip_id++; 28091da177e4SLinus Torvalds iph->frag_off = 0; 28101da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 28111da177e4SLinus Torvalds iph->tot_len = htons(iplen); 281203c633e7SThomas Graf ip_send_check(iph); 2813ca6549afSSteven Whitehouse skb->protocol = protocol; 28141da177e4SLinus Torvalds skb->dev = odev; 28151da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 2816c26bf4a5SThomas Graf 28177744b5f3SSabrina Dubroca pktgen_finalize_skb(pkt_dev, skb, datalen); 28187744b5f3SSabrina Dubroca 2819c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 2820c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 2821c8cd0989STom Herbert } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) { 2822c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 2823c26bf4a5SThomas Graf skb->csum = 0; 28247744b5f3SSabrina Dubroca udp4_hwcsum(skb, iph->saddr, iph->daddr); 2825c26bf4a5SThomas Graf } else { 28267744b5f3SSabrina Dubroca __wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0); 2827c26bf4a5SThomas Graf 2828c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 28297744b5f3SSabrina Dubroca udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 2830c26bf4a5SThomas Graf datalen + 8, IPPROTO_UDP, csum); 2831c26bf4a5SThomas Graf 2832c26bf4a5SThomas Graf if (udph->check == 0) 2833c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 2834c26bf4a5SThomas Graf } 2835c26bf4a5SThomas Graf 2836a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2837a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2838a553e4a6SJamal Hadi Salim return NULL; 2839a553e4a6SJamal Hadi Salim #endif 2840a553e4a6SJamal Hadi Salim 28411da177e4SLinus Torvalds return skb; 28421da177e4SLinus Torvalds } 28431da177e4SLinus Torvalds 28441da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 28451da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 28461da177e4SLinus Torvalds { 28471da177e4SLinus Torvalds struct sk_buff *skb = NULL; 28481da177e4SLinus Torvalds __u8 *eth; 28491da177e4SLinus Torvalds struct udphdr *udph; 2850c26bf4a5SThomas Graf int datalen, udplen; 28511da177e4SLinus Torvalds struct ipv6hdr *iph; 2852d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2853ca6549afSSteven Whitehouse __be32 *mpls; 285434954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 285534954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 285634954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 285734954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2858fd2ea0a7SDavid S. Miller u16 queue_map; 2859ca6549afSSteven Whitehouse 2860ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2861d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 28621da177e4SLinus Torvalds 286334954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2864d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 286534954ddcSFrancesco Fondelli 286664053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 286764053beeSRobert Olsson * fields. 286864053beeSRobert Olsson */ 286964053beeSRobert Olsson mod_cur_headers(pkt_dev); 2870eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 287164053beeSRobert Olsson 287263d75463SPaolo Abeni skb = pktgen_alloc_skb(odev, pkt_dev); 28731da177e4SLinus Torvalds if (!skb) { 28741da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 28751da177e4SLinus Torvalds return NULL; 28761da177e4SLinus Torvalds } 28771da177e4SLinus Torvalds 28787a6e288dSDaniel Borkmann prefetchw(skb->data); 28791da177e4SLinus Torvalds skb_reserve(skb, 16); 28801da177e4SLinus Torvalds 28811da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 2882d58ff351SJohannes Berg eth = skb_push(skb, 14); 28834df864c1SJohannes Berg mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 2884ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2885ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 288634954ddcSFrancesco Fondelli 288734954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 288834954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 28894df864c1SJohannes Berg svlan_tci = skb_put(skb, sizeof(__be16)); 28900f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 28910f37c605SAl Viro pkt_dev->svlan_cfi, 28920f37c605SAl Viro pkt_dev->svlan_p); 28934df864c1SJohannes Berg svlan_encapsulated_proto = skb_put(skb, 28944df864c1SJohannes Berg sizeof(__be16)); 2895d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 289634954ddcSFrancesco Fondelli } 28974df864c1SJohannes Berg vlan_tci = skb_put(skb, sizeof(__be16)); 28980f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 28990f37c605SAl Viro pkt_dev->vlan_cfi, 29000f37c605SAl Viro pkt_dev->vlan_p); 29014df864c1SJohannes Berg vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 2902d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 290334954ddcSFrancesco Fondelli } 290434954ddcSFrancesco Fondelli 2905c145aeb3SZhang Shengju skb_reset_mac_header(skb); 2906525cebedSThomas Graf skb_set_network_header(skb, skb->len); 29074df864c1SJohannes Berg iph = skb_put(skb, sizeof(struct ipv6hdr)); 2908525cebedSThomas Graf 2909525cebedSThomas Graf skb_set_transport_header(skb, skb->len); 29104df864c1SJohannes Berg udph = skb_put(skb, sizeof(struct udphdr)); 2911fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 29129e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 29131da177e4SLinus Torvalds 29141da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2915252e3346SAl Viro *(__be16 *) ð[12] = protocol; 29161da177e4SLinus Torvalds 2917ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2918ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 2919ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 292016dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 29211da177e4SLinus Torvalds 29225aa8b572SAmerigo Wang if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { 29231da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 2924e87cc472SJoe Perches net_info_ratelimited("increased datalen to %d\n", datalen); 29251da177e4SLinus Torvalds } 29261da177e4SLinus Torvalds 2927c26bf4a5SThomas Graf udplen = datalen + sizeof(struct udphdr); 29281da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 29291da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 2930c26bf4a5SThomas Graf udph->len = htons(udplen); 2931c26bf4a5SThomas Graf udph->check = 0; 29321da177e4SLinus Torvalds 2933d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 29341da177e4SLinus Torvalds 29351ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 29361ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 2937252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 29381ca7768cSFrancesco Fondelli } 29391ca7768cSFrancesco Fondelli 29401da177e4SLinus Torvalds iph->hop_limit = 32; 29411da177e4SLinus Torvalds 2942c26bf4a5SThomas Graf iph->payload_len = htons(udplen); 29431da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 29441da177e4SLinus Torvalds 29454e3fd7a0SAlexey Dobriyan iph->daddr = pkt_dev->cur_in6_daddr; 29464e3fd7a0SAlexey Dobriyan iph->saddr = pkt_dev->cur_in6_saddr; 29471da177e4SLinus Torvalds 2948ca6549afSSteven Whitehouse skb->protocol = protocol; 29491da177e4SLinus Torvalds skb->dev = odev; 29501da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 29511da177e4SLinus Torvalds 29527744b5f3SSabrina Dubroca pktgen_finalize_skb(pkt_dev, skb, datalen); 29537744b5f3SSabrina Dubroca 2954c26bf4a5SThomas Graf if (!(pkt_dev->flags & F_UDPCSUM)) { 2955c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_NONE; 2956c8cd0989STom Herbert } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) { 2957c26bf4a5SThomas Graf skb->ip_summed = CHECKSUM_PARTIAL; 2958c26bf4a5SThomas Graf skb->csum_start = skb_transport_header(skb) - skb->head; 2959c26bf4a5SThomas Graf skb->csum_offset = offsetof(struct udphdr, check); 2960c26bf4a5SThomas Graf udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0); 2961c26bf4a5SThomas Graf } else { 29627744b5f3SSabrina Dubroca __wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0); 2963c26bf4a5SThomas Graf 2964c26bf4a5SThomas Graf /* add protocol-dependent pseudo-header */ 2965c26bf4a5SThomas Graf udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum); 2966c26bf4a5SThomas Graf 2967c26bf4a5SThomas Graf if (udph->check == 0) 2968c26bf4a5SThomas Graf udph->check = CSUM_MANGLED_0; 2969c26bf4a5SThomas Graf } 2970c26bf4a5SThomas Graf 29711da177e4SLinus Torvalds return skb; 29721da177e4SLinus Torvalds } 29731da177e4SLinus Torvalds 2974475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 29751da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29761da177e4SLinus Torvalds { 29771da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 29781da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 29791da177e4SLinus Torvalds else 29801da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 29811da177e4SLinus Torvalds } 29821da177e4SLinus Torvalds 29831da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 29841da177e4SLinus Torvalds { 29851da177e4SLinus Torvalds pkt_dev->seq_num = 1; 29861da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 29871da177e4SLinus Torvalds pkt_dev->sofar = 0; 29881da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 29891da177e4SLinus Torvalds pkt_dev->errors = 0; 29901da177e4SLinus Torvalds } 29911da177e4SLinus Torvalds 29921da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 29931da177e4SLinus Torvalds 29941da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 29951da177e4SLinus Torvalds { 2996c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 29971da177e4SLinus Torvalds int started = 0; 29981da177e4SLinus Torvalds 2999f9467eaeSJoe Perches func_enter(); 30001da177e4SLinus Torvalds 30018788370aSJesper Dangaard Brouer rcu_read_lock(); 30028788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 30031da177e4SLinus Torvalds 30041da177e4SLinus Torvalds /* 30051da177e4SLinus Torvalds * setup odev and create initial packet. 30061da177e4SLinus Torvalds */ 30071da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds if (pkt_dev->odev) { 30101da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 30111da177e4SLinus Torvalds pkt_dev->skb = NULL; 3012398f382cSDaniel Borkmann pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); 3013fd29cf72SStephen Hemminger 301416dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 30151da177e4SLinus Torvalds 30161da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 30178788370aSJesper Dangaard Brouer pkt_dev->running = 1; /* Cranke yeself! */ 30181da177e4SLinus Torvalds started++; 3019222f1806SLuiz Capitulino } else 30201da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 30211da177e4SLinus Torvalds } 30228788370aSJesper Dangaard Brouer rcu_read_unlock(); 3023222f1806SLuiz Capitulino if (started) 3024222f1806SLuiz Capitulino t->control &= ~(T_STOP); 30251da177e4SLinus Torvalds } 30261da177e4SLinus Torvalds 3027*cda9de0bSYejune Deng static void pktgen_handle_all_threads(struct pktgen_net *pn, u32 flags) 30281da177e4SLinus Torvalds { 3029cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 30301da177e4SLinus Torvalds 30316146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3032cdcdbe0bSLuiz Capitulino 30334e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 3034*cda9de0bSYejune Deng t->control |= (flags); 3035cdcdbe0bSLuiz Capitulino 30366146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 30371da177e4SLinus Torvalds } 30381da177e4SLinus Torvalds 3039*cda9de0bSYejune Deng static void pktgen_stop_all_threads(struct pktgen_net *pn) 3040*cda9de0bSYejune Deng { 3041*cda9de0bSYejune Deng func_enter(); 3042*cda9de0bSYejune Deng 3043*cda9de0bSYejune Deng pktgen_handle_all_threads(pn, T_STOP); 3044*cda9de0bSYejune Deng } 3045*cda9de0bSYejune Deng 3046648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 30471da177e4SLinus Torvalds { 3048648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 30491da177e4SLinus Torvalds 30508788370aSJesper Dangaard Brouer rcu_read_lock(); 30518788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 30528788370aSJesper Dangaard Brouer if (pkt_dev->running) { 30538788370aSJesper Dangaard Brouer rcu_read_unlock(); 3054648fda74SStephen Hemminger return 1; 30558788370aSJesper Dangaard Brouer } 30568788370aSJesper Dangaard Brouer rcu_read_unlock(); 3057648fda74SStephen Hemminger return 0; 30581da177e4SLinus Torvalds } 30591da177e4SLinus Torvalds 30601da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 30611da177e4SLinus Torvalds { 30621da177e4SLinus Torvalds while (thread_is_running(t)) { 30631da177e4SLinus Torvalds 3064720f1de4SPaolo Abeni /* note: 't' will still be around even after the unlock/lock 3065720f1de4SPaolo Abeni * cycle because pktgen_thread threads are only cleared at 3066720f1de4SPaolo Abeni * net exit 3067720f1de4SPaolo Abeni */ 3068720f1de4SPaolo Abeni mutex_unlock(&pktgen_thread_lock); 30691da177e4SLinus Torvalds msleep_interruptible(100); 3070720f1de4SPaolo Abeni mutex_lock(&pktgen_thread_lock); 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds if (signal_pending(current)) 30731da177e4SLinus Torvalds goto signal; 30741da177e4SLinus Torvalds } 30751da177e4SLinus Torvalds return 1; 30761da177e4SLinus Torvalds signal: 30771da177e4SLinus Torvalds return 0; 30781da177e4SLinus Torvalds } 30791da177e4SLinus Torvalds 30804e58a027SCong Wang static int pktgen_wait_all_threads_run(struct pktgen_net *pn) 30811da177e4SLinus Torvalds { 3082cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 30831da177e4SLinus Torvalds int sig = 1; 30841da177e4SLinus Torvalds 3085720f1de4SPaolo Abeni /* prevent from racing with rmmod */ 3086720f1de4SPaolo Abeni if (!try_module_get(THIS_MODULE)) 3087720f1de4SPaolo Abeni return sig; 3088720f1de4SPaolo Abeni 30896146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3090cdcdbe0bSLuiz Capitulino 30914e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) { 30921da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3093222f1806SLuiz Capitulino if (sig == 0) 3094222f1806SLuiz Capitulino break; 30951da177e4SLinus Torvalds } 3096cdcdbe0bSLuiz Capitulino 3097cdcdbe0bSLuiz Capitulino if (sig == 0) 30984e58a027SCong Wang list_for_each_entry(t, &pn->pktgen_threads, th_list) 30991da177e4SLinus Torvalds t->control |= (T_STOP); 3100cdcdbe0bSLuiz Capitulino 31016146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 3102720f1de4SPaolo Abeni module_put(THIS_MODULE); 31031da177e4SLinus Torvalds return sig; 31041da177e4SLinus Torvalds } 31051da177e4SLinus Torvalds 31064e58a027SCong Wang static void pktgen_run_all_threads(struct pktgen_net *pn) 31071da177e4SLinus Torvalds { 3108f9467eaeSJoe Perches func_enter(); 31091da177e4SLinus Torvalds 3110*cda9de0bSYejune Deng pktgen_handle_all_threads(pn, T_RUN); 31111da177e4SLinus Torvalds 311263adc6fbSStephen Hemminger /* Propagate thread->control */ 311363adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 31141da177e4SLinus Torvalds 31154e58a027SCong Wang pktgen_wait_all_threads_run(pn); 31161da177e4SLinus Torvalds } 31171da177e4SLinus Torvalds 31184e58a027SCong Wang static void pktgen_reset_all_threads(struct pktgen_net *pn) 3119eb37b41cSJesse Brandeburg { 3120f9467eaeSJoe Perches func_enter(); 3121eb37b41cSJesse Brandeburg 3122*cda9de0bSYejune Deng pktgen_handle_all_threads(pn, T_REMDEVALL); 3123eb37b41cSJesse Brandeburg 312463adc6fbSStephen Hemminger /* Propagate thread->control */ 312563adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3126eb37b41cSJesse Brandeburg 31274e58a027SCong Wang pktgen_wait_all_threads_run(pn); 3128eb37b41cSJesse Brandeburg } 3129eb37b41cSJesse Brandeburg 31301da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 31311da177e4SLinus Torvalds { 3132fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 31331da177e4SLinus Torvalds char *p = pkt_dev->result; 3134fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3135fd29cf72SStephen Hemminger pkt_dev->started_at); 3136fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 31371da177e4SLinus Torvalds 313803a14ab1SDaniel Turull p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 3139fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3140fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3141fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 31421da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 31431da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 31441da177e4SLinus Torvalds 3145fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3146fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 31471da177e4SLinus Torvalds 31481da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 31491da177e4SLinus Torvalds 31501da177e4SLinus Torvalds mbps = bps; 31511da177e4SLinus Torvalds do_div(mbps, 1000000); 31521da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 31531da177e4SLinus Torvalds (unsigned long long)pps, 31541da177e4SLinus Torvalds (unsigned long long)mbps, 31551da177e4SLinus Torvalds (unsigned long long)bps, 31561da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 31571da177e4SLinus Torvalds } 31581da177e4SLinus Torvalds 31591da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 31601da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 31611da177e4SLinus Torvalds { 3162222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds if (!pkt_dev->running) { 3165294a0b7fSJoe Perches pr_warn("interface: %s is already stopped\n", 3166f9467eaeSJoe Perches pkt_dev->odevname); 31671da177e4SLinus Torvalds return -EINVAL; 31681da177e4SLinus Torvalds } 31691da177e4SLinus Torvalds 31708788370aSJesper Dangaard Brouer pkt_dev->running = 0; 31713bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 31723bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3173398f382cSDaniel Borkmann pkt_dev->stopped_at = ktime_get(); 31741da177e4SLinus Torvalds 317595ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 31761da177e4SLinus Torvalds 31771da177e4SLinus Torvalds return 0; 31781da177e4SLinus Torvalds } 31791da177e4SLinus Torvalds 31801da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 31811da177e4SLinus Torvalds { 3182c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 31831da177e4SLinus Torvalds 31848788370aSJesper Dangaard Brouer rcu_read_lock(); 31858788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3186c26a8016SLuiz Capitulino if (!pkt_dev->running) 3187222f1806SLuiz Capitulino continue; 3188222f1806SLuiz Capitulino if (best == NULL) 3189c26a8016SLuiz Capitulino best = pkt_dev; 3190398f382cSDaniel Borkmann else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) 3191c26a8016SLuiz Capitulino best = pkt_dev; 31921da177e4SLinus Torvalds } 31938788370aSJesper Dangaard Brouer rcu_read_unlock(); 31948788370aSJesper Dangaard Brouer 31951da177e4SLinus Torvalds return best; 31961da177e4SLinus Torvalds } 31971da177e4SLinus Torvalds 3198222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3199222f1806SLuiz Capitulino { 3200c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 32011da177e4SLinus Torvalds 3202f9467eaeSJoe Perches func_enter(); 32031da177e4SLinus Torvalds 32048788370aSJesper Dangaard Brouer rcu_read_lock(); 32051da177e4SLinus Torvalds 32068788370aSJesper Dangaard Brouer list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 3207c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 320895ed63f7SArthur Kepner } 320995ed63f7SArthur Kepner 32108788370aSJesper Dangaard Brouer rcu_read_unlock(); 321195ed63f7SArthur Kepner } 321295ed63f7SArthur Kepner 321395ed63f7SArthur Kepner /* 321495ed63f7SArthur Kepner * one of our devices needs to be removed - find it 321595ed63f7SArthur Kepner * and remove it 321695ed63f7SArthur Kepner */ 321795ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 321895ed63f7SArthur Kepner { 3219c26a8016SLuiz Capitulino struct list_head *q, *n; 3220c26a8016SLuiz Capitulino struct pktgen_dev *cur; 322195ed63f7SArthur Kepner 3222f9467eaeSJoe Perches func_enter(); 322395ed63f7SArthur Kepner 3224c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3225c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 322695ed63f7SArthur Kepner 3227222f1806SLuiz Capitulino if (!cur->removal_mark) 3228222f1806SLuiz Capitulino continue; 322995ed63f7SArthur Kepner 323095ed63f7SArthur Kepner kfree_skb(cur->skb); 323195ed63f7SArthur Kepner cur->skb = NULL; 323295ed63f7SArthur Kepner 323395ed63f7SArthur Kepner pktgen_remove_device(t, cur); 323495ed63f7SArthur Kepner 323595ed63f7SArthur Kepner break; 323695ed63f7SArthur Kepner } 32371da177e4SLinus Torvalds } 32381da177e4SLinus Torvalds 32391da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 32401da177e4SLinus Torvalds { 3241c26a8016SLuiz Capitulino struct list_head *q, *n; 3242c26a8016SLuiz Capitulino struct pktgen_dev *cur; 32431da177e4SLinus Torvalds 3244f9467eaeSJoe Perches func_enter(); 3245f9467eaeSJoe Perches 32461da177e4SLinus Torvalds /* Remove all devices, free mem */ 32471da177e4SLinus Torvalds 3248c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3249c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 325095ed63f7SArthur Kepner 325195ed63f7SArthur Kepner kfree_skb(cur->skb); 325295ed63f7SArthur Kepner cur->skb = NULL; 325395ed63f7SArthur Kepner 32541da177e4SLinus Torvalds pktgen_remove_device(t, cur); 32551da177e4SLinus Torvalds } 32561da177e4SLinus Torvalds } 32571da177e4SLinus Torvalds 32581da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 32591da177e4SLinus Torvalds { 32601da177e4SLinus Torvalds /* Remove from the thread list */ 32614e58a027SCong Wang remove_proc_entry(t->tsk->comm, t->net->proc_dir); 32621da177e4SLinus Torvalds } 32631da177e4SLinus Torvalds 3264ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 32653791decbSStephen Hemminger { 3266398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 32673791decbSStephen Hemminger schedule(); 3268398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 32693791decbSStephen Hemminger } 32703791decbSStephen Hemminger 3271ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3272ef87979cSStephen Hemminger { 3273398f382cSDaniel Borkmann ktime_t idle_start = ktime_get(); 3274ef87979cSStephen Hemminger 327563354797SReshetova, Elena while (refcount_read(&(pkt_dev->skb->users)) != 1) { 3276ef87979cSStephen Hemminger if (signal_pending(current)) 3277ef87979cSStephen Hemminger break; 3278ef87979cSStephen Hemminger 3279ef87979cSStephen Hemminger if (need_resched()) 3280ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3281ef87979cSStephen Hemminger else 3282ef87979cSStephen Hemminger cpu_relax(); 3283ef87979cSStephen Hemminger } 3284398f382cSDaniel Borkmann pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 3285ef87979cSStephen Hemminger } 3286fd29cf72SStephen Hemminger 3287475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 32881da177e4SLinus Torvalds { 32896aa7de05SMark Rutland unsigned int burst = READ_ONCE(pkt_dev->burst); 329000829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 3291fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 329262f64aedSAlexei Starovoitov struct sk_buff *skb; 32931da177e4SLinus Torvalds int ret; 32941da177e4SLinus Torvalds 3295ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3296ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 32971da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 32983791decbSStephen Hemminger return; 32991da177e4SLinus Torvalds } 33001da177e4SLinus Torvalds 3301ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3302ef87979cSStephen Hemminger * "never transmit" 3303ef87979cSStephen Hemminger */ 3304ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3305398f382cSDaniel Borkmann pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX); 3306ef87979cSStephen Hemminger return; 3307ef87979cSStephen Hemminger } 3308ef87979cSStephen Hemminger 3309ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 33107d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 33117d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 33121da177e4SLinus Torvalds /* build a new pkt */ 33131da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 33141da177e4SLinus Torvalds 33151da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 33161da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3317f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 33181da177e4SLinus Torvalds schedule(); 33191da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 33203791decbSStephen Hemminger return; 33211da177e4SLinus Torvalds } 3322baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 33231da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 33241da177e4SLinus Torvalds } 33251da177e4SLinus Torvalds 3326ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3327ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3328ef87979cSStephen Hemminger 332962f64aedSAlexei Starovoitov if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) { 333062f64aedSAlexei Starovoitov skb = pkt_dev->skb; 333162f64aedSAlexei Starovoitov skb->protocol = eth_type_trans(skb, skb->dev); 333263354797SReshetova, Elena refcount_add(burst, &skb->users); 333362f64aedSAlexei Starovoitov local_bh_disable(); 333462f64aedSAlexei Starovoitov do { 333562f64aedSAlexei Starovoitov ret = netif_receive_skb(skb); 333662f64aedSAlexei Starovoitov if (ret == NET_RX_DROP) 333762f64aedSAlexei Starovoitov pkt_dev->errors++; 333862f64aedSAlexei Starovoitov pkt_dev->sofar++; 333962f64aedSAlexei Starovoitov pkt_dev->seq_num++; 334063354797SReshetova, Elena if (refcount_read(&skb->users) != burst) { 334162f64aedSAlexei Starovoitov /* skb was queued by rps/rfs or taps, 334262f64aedSAlexei Starovoitov * so cannot reuse this skb 334362f64aedSAlexei Starovoitov */ 334463354797SReshetova, Elena WARN_ON(refcount_sub_and_test(burst - 1, &skb->users)); 334562f64aedSAlexei Starovoitov /* get out of the loop and wait 334662f64aedSAlexei Starovoitov * until skb is consumed 334762f64aedSAlexei Starovoitov */ 334862f64aedSAlexei Starovoitov break; 334962f64aedSAlexei Starovoitov } 335062f64aedSAlexei Starovoitov /* skb was 'freed' by stack, so clean few 335162f64aedSAlexei Starovoitov * bits and reuse it 335262f64aedSAlexei Starovoitov */ 33532c64605bSPablo Neira Ayuso skb_reset_redirect(skb); 335462f64aedSAlexei Starovoitov } while (--burst > 0); 335562f64aedSAlexei Starovoitov goto out; /* Skips xmit_mode M_START_XMIT */ 33560967f244SJohn Fastabend } else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) { 33570967f244SJohn Fastabend local_bh_disable(); 335863354797SReshetova, Elena refcount_inc(&pkt_dev->skb->users); 33590967f244SJohn Fastabend 33600967f244SJohn Fastabend ret = dev_queue_xmit(pkt_dev->skb); 33610967f244SJohn Fastabend switch (ret) { 33620967f244SJohn Fastabend case NET_XMIT_SUCCESS: 33630967f244SJohn Fastabend pkt_dev->sofar++; 33640967f244SJohn Fastabend pkt_dev->seq_num++; 33650967f244SJohn Fastabend pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 33660967f244SJohn Fastabend break; 33670967f244SJohn Fastabend case NET_XMIT_DROP: 33680967f244SJohn Fastabend case NET_XMIT_CN: 33690967f244SJohn Fastabend /* These are all valid return codes for a qdisc but 33700967f244SJohn Fastabend * indicate packets are being dropped or will likely 33710967f244SJohn Fastabend * be dropped soon. 33720967f244SJohn Fastabend */ 33730967f244SJohn Fastabend case NETDEV_TX_BUSY: 33740967f244SJohn Fastabend /* qdisc may call dev_hard_start_xmit directly in cases 33750967f244SJohn Fastabend * where no queues exist e.g. loopback device, virtual 33760967f244SJohn Fastabend * devices, etc. In this case we need to handle 33770967f244SJohn Fastabend * NETDEV_TX_ codes. 33780967f244SJohn Fastabend */ 33790967f244SJohn Fastabend default: 33800967f244SJohn Fastabend pkt_dev->errors++; 33810967f244SJohn Fastabend net_info_ratelimited("%s xmit error: %d\n", 33820967f244SJohn Fastabend pkt_dev->odevname, ret); 33830967f244SJohn Fastabend break; 33840967f244SJohn Fastabend } 33850967f244SJohn Fastabend goto out; 338662f64aedSAlexei Starovoitov } 338762f64aedSAlexei Starovoitov 338810c51b56SDaniel Borkmann txq = skb_get_tx_queue(odev, pkt_dev->skb); 3389fd2ea0a7SDavid S. Miller 33900f2eea4bSDaniel Borkmann local_bh_disable(); 33910f2eea4bSDaniel Borkmann 33920f2eea4bSDaniel Borkmann HARD_TX_LOCK(odev, txq, smp_processor_id()); 33935b8db2f5SStephen Hemminger 33946f25cd47SDaniel Borkmann if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) { 33950835acfeSEric Dumazet pkt_dev->last_ok = 0; 33960835acfeSEric Dumazet goto unlock; 33970835acfeSEric Dumazet } 339863354797SReshetova, Elena refcount_add(burst, &pkt_dev->skb->users); 339938b2cf29SAlexei Starovoitov 340038b2cf29SAlexei Starovoitov xmit_more: 340138b2cf29SAlexei Starovoitov ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); 3402ef87979cSStephen Hemminger 34035b8db2f5SStephen Hemminger switch (ret) { 34045b8db2f5SStephen Hemminger case NETDEV_TX_OK: 34051da177e4SLinus Torvalds pkt_dev->last_ok = 1; 34061da177e4SLinus Torvalds pkt_dev->sofar++; 34071da177e4SLinus Torvalds pkt_dev->seq_num++; 3408baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 340938b2cf29SAlexei Starovoitov if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq)) 341038b2cf29SAlexei Starovoitov goto xmit_more; 34115b8db2f5SStephen Hemminger break; 3412f466dba1SJohn Fastabend case NET_XMIT_DROP: 3413f466dba1SJohn Fastabend case NET_XMIT_CN: 3414f466dba1SJohn Fastabend /* skb has been consumed */ 3415f466dba1SJohn Fastabend pkt_dev->errors++; 3416f466dba1SJohn Fastabend break; 34175b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 3418e87cc472SJoe Perches net_info_ratelimited("%s xmit error: %d\n", 3419e87cc472SJoe Perches pkt_dev->odevname, ret); 34201da177e4SLinus Torvalds pkt_dev->errors++; 3421df561f66SGustavo A. R. Silva fallthrough; 34225b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 34235b8db2f5SStephen Hemminger /* Retry it next time */ 342463354797SReshetova, Elena refcount_dec(&(pkt_dev->skb->users)); 34251da177e4SLinus Torvalds pkt_dev->last_ok = 0; 34261da177e4SLinus Torvalds } 342738b2cf29SAlexei Starovoitov if (unlikely(burst)) 342863354797SReshetova, Elena WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users)); 34290835acfeSEric Dumazet unlock: 34300f2eea4bSDaniel Borkmann HARD_TX_UNLOCK(odev, txq); 34310f2eea4bSDaniel Borkmann 343262f64aedSAlexei Starovoitov out: 34330f2eea4bSDaniel Borkmann local_bh_enable(); 34341da177e4SLinus Torvalds 34351da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 34361da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3437ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 34381da177e4SLinus Torvalds 34391da177e4SLinus Torvalds /* Done with this */ 34401da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34411da177e4SLinus Torvalds } 34421da177e4SLinus Torvalds } 34431da177e4SLinus Torvalds 34441da177e4SLinus Torvalds /* 34451da177e4SLinus Torvalds * Main loop of the thread goes here 34461da177e4SLinus Torvalds */ 34471da177e4SLinus Torvalds 3448ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 34491da177e4SLinus Torvalds { 34501da177e4SLinus Torvalds DEFINE_WAIT(wait); 3451ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 34521da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 34531da177e4SLinus Torvalds int cpu = t->cpu; 34541da177e4SLinus Torvalds 3455275b1e88SDi Zhu WARN_ON(smp_processor_id() != cpu); 34561da177e4SLinus Torvalds 34571da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3458d3ede327SDenis V. Lunev complete(&t->start_done); 34591da177e4SLinus Torvalds 3460f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 34611da177e4SLinus Torvalds 346283144186SRafael J. Wysocki set_freezable(); 346383144186SRafael J. Wysocki 3464ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3465ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3466ee74baa7SDavid S. Miller 3467ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 34684e58a027SCong Wang if (t->net->pktgen_exiting) 3469551eaff1SEric Dumazet break; 3470ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3471ef87979cSStephen Hemminger t->control != 0, 3472ef87979cSStephen Hemminger HZ/10); 34731b3f720bSRafael J. Wysocki try_to_freeze(); 3474ef87979cSStephen Hemminger continue; 3475ee74baa7SDavid S. Miller } 34761da177e4SLinus Torvalds 3477ef87979cSStephen Hemminger if (likely(pkt_dev)) { 34781da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 34791da177e4SLinus Torvalds 3480ef87979cSStephen Hemminger if (need_resched()) 3481ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3482ef87979cSStephen Hemminger else 3483ef87979cSStephen Hemminger cpu_relax(); 3484ef87979cSStephen Hemminger } 3485ef87979cSStephen Hemminger 34861da177e4SLinus Torvalds if (t->control & T_STOP) { 34871da177e4SLinus Torvalds pktgen_stop(t); 34881da177e4SLinus Torvalds t->control &= ~(T_STOP); 34891da177e4SLinus Torvalds } 34901da177e4SLinus Torvalds 34911da177e4SLinus Torvalds if (t->control & T_RUN) { 34921da177e4SLinus Torvalds pktgen_run(t); 34931da177e4SLinus Torvalds t->control &= ~(T_RUN); 34941da177e4SLinus Torvalds } 34951da177e4SLinus Torvalds 349695ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 34971da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 349895ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 349995ed63f7SArthur Kepner } 350095ed63f7SArthur Kepner 350195ed63f7SArthur Kepner if (t->control & T_REMDEV) { 350295ed63f7SArthur Kepner pktgen_rem_one_if(t); 35031da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 35041da177e4SLinus Torvalds } 35051da177e4SLinus Torvalds 350609fe3ef4SAndrew Morton try_to_freeze(); 35071da177e4SLinus Torvalds } 35081da177e4SLinus Torvalds 3509f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 35101da177e4SLinus Torvalds pktgen_stop(t); 35111da177e4SLinus Torvalds 3512f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 35131da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 35141da177e4SLinus Torvalds 3515f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 35161da177e4SLinus Torvalds pktgen_rem_thread(t); 3517cdcdbe0bSLuiz Capitulino 3518ee74baa7SDavid S. Miller return 0; 35191da177e4SLinus Torvalds } 35201da177e4SLinus Torvalds 3521222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 35223e984840SEric Dumazet const char *ifname, bool exact) 35231da177e4SLinus Torvalds { 3524c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 35253e984840SEric Dumazet size_t len = strlen(ifname); 35261da177e4SLinus Torvalds 35278788370aSJesper Dangaard Brouer rcu_read_lock(); 35288788370aSJesper Dangaard Brouer list_for_each_entry_rcu(p, &t->if_list, list) 35293e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 35303e984840SEric Dumazet if (p->odevname[len]) { 35313e984840SEric Dumazet if (exact || p->odevname[len] != '@') 35323e984840SEric Dumazet continue; 35333e984840SEric Dumazet } 3534c26a8016SLuiz Capitulino pkt_dev = p; 35351da177e4SLinus Torvalds break; 35361da177e4SLinus Torvalds } 35371da177e4SLinus Torvalds 35388788370aSJesper Dangaard Brouer rcu_read_unlock(); 3539f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 35401da177e4SLinus Torvalds return pkt_dev; 35411da177e4SLinus Torvalds } 35421da177e4SLinus Torvalds 35431da177e4SLinus Torvalds /* 35441da177e4SLinus Torvalds * Adds a dev at front of if_list. 35451da177e4SLinus Torvalds */ 35461da177e4SLinus Torvalds 3547222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3548222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 35491da177e4SLinus Torvalds { 35501da177e4SLinus Torvalds int rv = 0; 35511da177e4SLinus Torvalds 35528788370aSJesper Dangaard Brouer /* This function cannot be called concurrently, as its called 35538788370aSJesper Dangaard Brouer * under pktgen_thread_lock mutex, but it can run from 35548788370aSJesper Dangaard Brouer * userspace on another CPU than the kthread. The if_lock() 35558788370aSJesper Dangaard Brouer * is used here to sync with concurrent instances of 35568788370aSJesper Dangaard Brouer * _rem_dev_from_if_list() invoked via kthread, which is also 35578788370aSJesper Dangaard Brouer * updating the if_list */ 35581da177e4SLinus Torvalds if_lock(t); 35591da177e4SLinus Torvalds 35601da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3561f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 35621da177e4SLinus Torvalds rv = -EBUSY; 35631da177e4SLinus Torvalds goto out; 35641da177e4SLinus Torvalds } 3565c26a8016SLuiz Capitulino 35661da177e4SLinus Torvalds pkt_dev->running = 0; 35678788370aSJesper Dangaard Brouer pkt_dev->pg_thread = t; 35688788370aSJesper Dangaard Brouer list_add_rcu(&pkt_dev->list, &t->if_list); 35691da177e4SLinus Torvalds 35701da177e4SLinus Torvalds out: 35711da177e4SLinus Torvalds if_unlock(t); 35721da177e4SLinus Torvalds return rv; 35731da177e4SLinus Torvalds } 35741da177e4SLinus Torvalds 35751da177e4SLinus Torvalds /* Called under thread lock */ 35761da177e4SLinus Torvalds 35771da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 35781da177e4SLinus Torvalds { 35791da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 358039df232fSStephen Hemminger int err; 35813291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 35821da177e4SLinus Torvalds 35831da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 35841da177e4SLinus Torvalds 35854e58a027SCong Wang pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND); 3586d50a6b56SStephen Hemminger if (pkt_dev) { 3587f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3588d50a6b56SStephen Hemminger return -EBUSY; 3589d50a6b56SStephen Hemminger } 35901da177e4SLinus Torvalds 35913291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 35921da177e4SLinus Torvalds if (!pkt_dev) 35931da177e4SLinus Torvalds return -ENOMEM; 35941da177e4SLinus Torvalds 3595593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 3596fd7becedSKees Cook pkt_dev->flows = vzalloc_node(array_size(MAX_CFLOWS, 3597fd7becedSKees Cook sizeof(struct flow_state)), 35983291b9dbSEric Dumazet node); 35991da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 36001da177e4SLinus Torvalds kfree(pkt_dev); 36011da177e4SLinus Torvalds return -ENOMEM; 36021da177e4SLinus Torvalds } 36031da177e4SLinus Torvalds 360495ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 36051da177e4SLinus Torvalds pkt_dev->nfrags = 0; 3606fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 36071da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 36081da177e4SLinus Torvalds pkt_dev->sofar = 0; 36091da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 36101da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 36111da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 36121da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 361334954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 361434954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 361534954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 361634954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 361734954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 361834954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 361938b2cf29SAlexei Starovoitov pkt_dev->burst = 1; 362098fa15f3SAnshuman Khandual pkt_dev->node = NUMA_NO_NODE; 362134954ddcSFrancesco Fondelli 36224e58a027SCong Wang err = pktgen_setup_dev(t->net, pkt_dev, ifname); 362339df232fSStephen Hemminger if (err) 362439df232fSStephen Hemminger goto out1; 3625d8873315SNeil Horman if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) 3626d8873315SNeil Horman pkt_dev->clone_skb = pg_clone_skb_d; 36271da177e4SLinus Torvalds 36284e58a027SCong Wang pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir, 362997a32539SAlexey Dobriyan &pktgen_if_proc_ops, pkt_dev); 363039df232fSStephen Hemminger if (!pkt_dev->entry) { 3631f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3632d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 363339df232fSStephen Hemminger err = -EINVAL; 363439df232fSStephen Hemminger goto out2; 363539df232fSStephen Hemminger } 3636a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3637a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3638a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3639cf93d47eSFan Du 3640cf93d47eSFan Du /* xfrm tunnel mode needs additional dst to extract outter 3641cf93d47eSFan Du * ip header protocol/ttl/id field, here creat a phony one. 3642cf93d47eSFan Du * instead of looking for a valid rt, which definitely hurting 3643cf93d47eSFan Du * performance under such circumstance. 3644cf93d47eSFan Du */ 3645cf93d47eSFan Du pkt_dev->dstops.family = AF_INET; 3646b6ca8bd5SDavid Miller pkt_dev->xdst.u.dst.dev = pkt_dev->odev; 3647b6ca8bd5SDavid Miller dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false); 3648b6ca8bd5SDavid Miller pkt_dev->xdst.child = &pkt_dev->xdst.u.dst; 3649b6ca8bd5SDavid Miller pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops; 3650a553e4a6SJamal Hadi Salim #endif 365139df232fSStephen Hemminger 365239df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 365339df232fSStephen Hemminger out2: 365439df232fSStephen Hemminger dev_put(pkt_dev->odev); 365539df232fSStephen Hemminger out1: 3656a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3657a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3658a553e4a6SJamal Hadi Salim #endif 36591da177e4SLinus Torvalds vfree(pkt_dev->flows); 36601da177e4SLinus Torvalds kfree(pkt_dev); 366139df232fSStephen Hemminger return err; 36621da177e4SLinus Torvalds } 36631da177e4SLinus Torvalds 36644e58a027SCong Wang static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) 36651da177e4SLinus Torvalds { 3666cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3667d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3668ee74baa7SDavid S. Miller struct task_struct *p; 36691da177e4SLinus Torvalds 36703291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 36713291b9dbSEric Dumazet cpu_to_node(cpu)); 36721da177e4SLinus Torvalds if (!t) { 3673f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 36741da177e4SLinus Torvalds return -ENOMEM; 36751da177e4SLinus Torvalds } 36761da177e4SLinus Torvalds 36779a0b1e8bSEric Dumazet mutex_init(&t->if_lock); 36781da177e4SLinus Torvalds t->cpu = cpu; 36791da177e4SLinus Torvalds 3680ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3681ee74baa7SDavid S. Miller 36824e58a027SCong Wang list_add_tail(&t->th_list, &pn->pktgen_threads); 3683d3ede327SDenis V. Lunev init_completion(&t->start_done); 3684ee74baa7SDavid S. Miller 368594dcf29aSEric Dumazet p = kthread_create_on_node(pktgen_thread_worker, 368694dcf29aSEric Dumazet t, 368794dcf29aSEric Dumazet cpu_to_node(cpu), 368894dcf29aSEric Dumazet "kpktgend_%d", cpu); 3689ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3690355db391SLeesoo Ahn pr_err("kthread_create_on_node() failed for cpu %d\n", t->cpu); 3691ee74baa7SDavid S. Miller list_del(&t->th_list); 3692ee74baa7SDavid S. Miller kfree(t); 3693ee74baa7SDavid S. Miller return PTR_ERR(p); 3694ee74baa7SDavid S. Miller } 3695ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3696ee74baa7SDavid S. Miller t->tsk = p; 3697ee74baa7SDavid S. Miller 36984e58a027SCong Wang pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir, 369997a32539SAlexey Dobriyan &pktgen_thread_proc_ops, t); 3700d50a6b56SStephen Hemminger if (!pe) { 3701f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3702ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3703ee74baa7SDavid S. Miller kthread_stop(p); 3704ee74baa7SDavid S. Miller list_del(&t->th_list); 37051da177e4SLinus Torvalds kfree(t); 37061da177e4SLinus Torvalds return -EINVAL; 37071da177e4SLinus Torvalds } 3708d50a6b56SStephen Hemminger 37094e58a027SCong Wang t->net = pn; 37101fbe4b46SOleg Nesterov get_task_struct(p); 3711ee74baa7SDavid S. Miller wake_up_process(p); 3712d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 37131da177e4SLinus Torvalds 37141da177e4SLinus Torvalds return 0; 37151da177e4SLinus Torvalds } 37161da177e4SLinus Torvalds 37171da177e4SLinus Torvalds /* 37181da177e4SLinus Torvalds * Removes a device from the thread if_list. 37191da177e4SLinus Torvalds */ 3720222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3721222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 37221da177e4SLinus Torvalds { 3723c26a8016SLuiz Capitulino struct list_head *q, *n; 3724c26a8016SLuiz Capitulino struct pktgen_dev *p; 37251da177e4SLinus Torvalds 37268788370aSJesper Dangaard Brouer if_lock(t); 3727c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3728c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3729c26a8016SLuiz Capitulino if (p == pkt_dev) 37308788370aSJesper Dangaard Brouer list_del_rcu(&p->list); 37311da177e4SLinus Torvalds } 37328788370aSJesper Dangaard Brouer if_unlock(t); 37331da177e4SLinus Torvalds } 37341da177e4SLinus Torvalds 3735222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3736222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 37371da177e4SLinus Torvalds { 3738f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 37391da177e4SLinus Torvalds 37401da177e4SLinus Torvalds if (pkt_dev->running) { 3741294a0b7fSJoe Perches pr_warn("WARNING: trying to remove a running interface, stopping it now\n"); 37421da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 37431da177e4SLinus Torvalds } 37441da177e4SLinus Torvalds 37451da177e4SLinus Torvalds /* Dis-associate from the interface */ 37461da177e4SLinus Torvalds 37471da177e4SLinus Torvalds if (pkt_dev->odev) { 37481da177e4SLinus Torvalds dev_put(pkt_dev->odev); 37491da177e4SLinus Torvalds pkt_dev->odev = NULL; 37501da177e4SLinus Torvalds } 37511da177e4SLinus Torvalds 37528788370aSJesper Dangaard Brouer /* Remove proc before if_list entry, because add_device uses 37538788370aSJesper Dangaard Brouer * list to determine if interface already exist, avoid race 37548788370aSJesper Dangaard Brouer * with proc_create_data() */ 3755a8ca16eaSDavid Howells proc_remove(pkt_dev->entry); 37561da177e4SLinus Torvalds 37578788370aSJesper Dangaard Brouer /* And update the thread if_list */ 37588788370aSJesper Dangaard Brouer _rem_dev_from_if_list(t, pkt_dev); 37598788370aSJesper Dangaard Brouer 3760a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3761a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3762a553e4a6SJamal Hadi Salim #endif 37631da177e4SLinus Torvalds vfree(pkt_dev->flows); 376426ad7879SEric Dumazet if (pkt_dev->page) 376526ad7879SEric Dumazet put_page(pkt_dev->page); 37668788370aSJesper Dangaard Brouer kfree_rcu(pkt_dev, rcu); 37671da177e4SLinus Torvalds return 0; 37681da177e4SLinus Torvalds } 37691da177e4SLinus Torvalds 37704e58a027SCong Wang static int __net_init pg_net_init(struct net *net) 37711da177e4SLinus Torvalds { 37724e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3773d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 37744e58a027SCong Wang int cpu, ret = 0; 3775d50a6b56SStephen Hemminger 37764e58a027SCong Wang pn->net = net; 37774e58a027SCong Wang INIT_LIST_HEAD(&pn->pktgen_threads); 37784e58a027SCong Wang pn->pktgen_exiting = false; 37794e58a027SCong Wang pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net); 37804e58a027SCong Wang if (!pn->proc_dir) { 37814e58a027SCong Wang pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); 3782d50a6b56SStephen Hemminger return -ENODEV; 37831da177e4SLinus Torvalds } 378497a32539SAlexey Dobriyan pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_proc_ops); 37854e58a027SCong Wang if (pe == NULL) { 37864e58a027SCong Wang pr_err("cannot create %s procfs entry\n", PGCTRL); 37874e58a027SCong Wang ret = -EINVAL; 37884e58a027SCong Wang goto remove; 37894e58a027SCong Wang } 37901da177e4SLinus Torvalds 3791670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 37928024bb24SLuiz Capitulino int err; 37931da177e4SLinus Torvalds 37944e58a027SCong Wang err = pktgen_create_thread(cpu, pn); 37958024bb24SLuiz Capitulino if (err) 37964e58a027SCong Wang pr_warn("Cannot create thread for cpu %d (%d)\n", 3797f9467eaeSJoe Perches cpu, err); 37981da177e4SLinus Torvalds } 37998024bb24SLuiz Capitulino 38004e58a027SCong Wang if (list_empty(&pn->pktgen_threads)) { 38014e58a027SCong Wang pr_err("Initialization failed for all threads\n"); 3802ce14f894SWANG Cong ret = -ENODEV; 38034e58a027SCong Wang goto remove_entry; 38048024bb24SLuiz Capitulino } 38058024bb24SLuiz Capitulino 38061da177e4SLinus Torvalds return 0; 3807ce14f894SWANG Cong 38084e58a027SCong Wang remove_entry: 38094e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 38104e58a027SCong Wang remove: 3811ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 3812ce14f894SWANG Cong return ret; 38131da177e4SLinus Torvalds } 38141da177e4SLinus Torvalds 38154e58a027SCong Wang static void __net_exit pg_net_exit(struct net *net) 38161da177e4SLinus Torvalds { 38174e58a027SCong Wang struct pktgen_net *pn = net_generic(net, pg_net_id); 3818cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3819cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 3820d4b11335SEric Dumazet LIST_HEAD(list); 38211da177e4SLinus Torvalds 38221da177e4SLinus Torvalds /* Stop all interfaces & threads */ 38234e58a027SCong Wang pn->pktgen_exiting = true; 38241da177e4SLinus Torvalds 3825c57b5468SEric Dumazet mutex_lock(&pktgen_thread_lock); 38264e58a027SCong Wang list_splice_init(&pn->pktgen_threads, &list); 3827c57b5468SEric Dumazet mutex_unlock(&pktgen_thread_lock); 3828c57b5468SEric Dumazet 3829c57b5468SEric Dumazet list_for_each_safe(q, n, &list) { 3830cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3831c57b5468SEric Dumazet list_del(&t->th_list); 3832ee74baa7SDavid S. Miller kthread_stop(t->tsk); 38331fbe4b46SOleg Nesterov put_task_struct(t->tsk); 3834ee74baa7SDavid S. Miller kfree(t); 38351da177e4SLinus Torvalds } 38361da177e4SLinus Torvalds 38374e58a027SCong Wang remove_proc_entry(PGCTRL, pn->proc_dir); 3838ece31ffdSGao feng remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 38394e58a027SCong Wang } 38401da177e4SLinus Torvalds 38414e58a027SCong Wang static struct pernet_operations pg_net_ops = { 38424e58a027SCong Wang .init = pg_net_init, 38434e58a027SCong Wang .exit = pg_net_exit, 38444e58a027SCong Wang .id = &pg_net_id, 38454e58a027SCong Wang .size = sizeof(struct pktgen_net), 38464e58a027SCong Wang }; 38474e58a027SCong Wang 38484e58a027SCong Wang static int __init pg_init(void) 38494e58a027SCong Wang { 38504e58a027SCong Wang int ret = 0; 38514e58a027SCong Wang 38524e58a027SCong Wang pr_info("%s", version); 38534e58a027SCong Wang ret = register_pernet_subsys(&pg_net_ops); 38544e58a027SCong Wang if (ret) 38554e58a027SCong Wang return ret; 38564e58a027SCong Wang ret = register_netdevice_notifier(&pktgen_notifier_block); 38574e58a027SCong Wang if (ret) 38584e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 38594e58a027SCong Wang 38604e58a027SCong Wang return ret; 38614e58a027SCong Wang } 38624e58a027SCong Wang 38634e58a027SCong Wang static void __exit pg_cleanup(void) 38644e58a027SCong Wang { 38654e58a027SCong Wang unregister_netdevice_notifier(&pktgen_notifier_block); 38664e58a027SCong Wang unregister_pernet_subsys(&pg_net_ops); 38678788370aSJesper Dangaard Brouer /* Don't need rcu_barrier() due to use of kfree_rcu() */ 38681da177e4SLinus Torvalds } 38691da177e4SLinus Torvalds 38701da177e4SLinus Torvalds module_init(pg_init); 38711da177e4SLinus Torvalds module_exit(pg_cleanup); 38721da177e4SLinus Torvalds 3873c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 38741da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 38751da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3876c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 38771da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3878c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 38791da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3880c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 38811da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3882c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 38831da177e4SLinus Torvalds module_param(debug, int, 0); 3884c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3885