18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Authors: 48c2ecf20Sopenharmony_ci * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> 58c2ecf20Sopenharmony_ci * Uppsala University and 68c2ecf20Sopenharmony_ci * Swedish University of Agricultural Sciences 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 98c2ecf20Sopenharmony_ci * Ben Greear <greearb@candelatech.com> 108c2ecf20Sopenharmony_ci * Jens Låås <jens.laas@data.slu.se> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * A tool for loading the network with preconfigurated packets. 138c2ecf20Sopenharmony_ci * The tool is implemented as a linux module. Parameters are output 148c2ecf20Sopenharmony_ci * device, delay (to hard_xmit), number of packets, and whether 158c2ecf20Sopenharmony_ci * to use multiple SKBs or just the same one. 168c2ecf20Sopenharmony_ci * pktgen uses the installed interface's output routine. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Additional hacking by: 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Jens.Laas@data.slu.se 218c2ecf20Sopenharmony_ci * Improved by ANK. 010120. 228c2ecf20Sopenharmony_ci * Improved by ANK even more. 010212. 238c2ecf20Sopenharmony_ci * MAC address typo fixed. 010417 --ro 248c2ecf20Sopenharmony_ci * Integrated. 020301 --DaveM 258c2ecf20Sopenharmony_ci * Added multiskb option 020301 --DaveM 268c2ecf20Sopenharmony_ci * Scaling of results. 020417--sigurdur@linpro.no 278c2ecf20Sopenharmony_ci * Significant re-work of the module: 288c2ecf20Sopenharmony_ci * * Convert to threaded model to more efficiently be able to transmit 298c2ecf20Sopenharmony_ci * and receive on multiple interfaces at once. 308c2ecf20Sopenharmony_ci * * Converted many counters to __u64 to allow longer runs. 318c2ecf20Sopenharmony_ci * * Allow configuration of ranges, like min/max IP address, MACs, 328c2ecf20Sopenharmony_ci * and UDP-ports, for both source and destination, and can 338c2ecf20Sopenharmony_ci * set to use a random distribution or sequentially walk the range. 348c2ecf20Sopenharmony_ci * * Can now change most values after starting. 358c2ecf20Sopenharmony_ci * * Place 12-byte packet in UDP payload with magic number, 368c2ecf20Sopenharmony_ci * sequence number, and timestamp. 378c2ecf20Sopenharmony_ci * * Add receiver code that detects dropped pkts, re-ordered pkts, and 388c2ecf20Sopenharmony_ci * latencies (with micro-second) precision. 398c2ecf20Sopenharmony_ci * * Add IOCTL interface to easily get counters & configuration. 408c2ecf20Sopenharmony_ci * --Ben Greear <greearb@candelatech.com> 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 438c2ecf20Sopenharmony_ci * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 448c2ecf20Sopenharmony_ci * as a "fastpath" with a configurable number of clones after alloc's. 458c2ecf20Sopenharmony_ci * clone_skb=0 means all packets are allocated this also means ranges time 468c2ecf20Sopenharmony_ci * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 478c2ecf20Sopenharmony_ci * clones. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Also moved to /proc/net/pktgen/ 508c2ecf20Sopenharmony_ci * --ro 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever 538c2ecf20Sopenharmony_ci * mistakes. Also merged in DaveM's patch in the -pre6 patch. 548c2ecf20Sopenharmony_ci * --Ben Greear <greearb@candelatech.com> 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * 021124 Finished major redesign and rewrite for new functionality. 598c2ecf20Sopenharmony_ci * See Documentation/networking/pktgen.rst for how to use this. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * The new operation: 628c2ecf20Sopenharmony_ci * For each CPU one thread/process is created at start. This process checks 638c2ecf20Sopenharmony_ci * for running devices in the if_list and sends packets until count is 0 it 648c2ecf20Sopenharmony_ci * also the thread checks the thread->control which is used for inter-process 658c2ecf20Sopenharmony_ci * communication. controlling process "posts" operations to the threads this 668c2ecf20Sopenharmony_ci * way. 678c2ecf20Sopenharmony_ci * The if_list is RCU protected, and the if_lock remains to protect updating 688c2ecf20Sopenharmony_ci * of if_list, from "add_device" as it invoked from userspace (via proc write). 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * By design there should only be *one* "controlling" process. In practice 718c2ecf20Sopenharmony_ci * multiple write accesses gives unpredictable result. Understood by "write" 728c2ecf20Sopenharmony_ci * to /proc gives result code thats should be read be the "writer". 738c2ecf20Sopenharmony_ci * For practical use this should be no problem. 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * Note when adding devices to a specific CPU there good idea to also assign 768c2ecf20Sopenharmony_ci * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 778c2ecf20Sopenharmony_ci * --ro 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * Fix refcount off by one if first packet fails, potential null deref, 808c2ecf20Sopenharmony_ci * memleak 030710- KJP 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * First "ranges" functionality for ipv6 030726 --ro 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Included flow support. 030802 ANK. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 898c2ecf20Sopenharmony_ci * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * New xmit() return, do_div and misc clean up by Stephen Hemminger 928c2ecf20Sopenharmony_ci * <shemminger@osdl.org> 040923 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * Randy Dunlap fixed u64 printk compiler warning 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> 978c2ecf20Sopenharmony_ci * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * Corrections from Nikolai Malykh (nmalykh@bilim.com) 1008c2ecf20Sopenharmony_ci * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 1038c2ecf20Sopenharmony_ci * 050103 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * MPLS support by Steven Whitehouse <steve@chygwyn.com> 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * Fixed src_mac command to set source mac of packet to value specified in 1108c2ecf20Sopenharmony_ci * command by Adit Ranadive <adit.262@gmail.com> 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#include <linux/sys.h> 1168c2ecf20Sopenharmony_ci#include <linux/types.h> 1178c2ecf20Sopenharmony_ci#include <linux/module.h> 1188c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 1198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 1208c2ecf20Sopenharmony_ci#include <linux/mutex.h> 1218c2ecf20Sopenharmony_ci#include <linux/sched.h> 1228c2ecf20Sopenharmony_ci#include <linux/slab.h> 1238c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 1248c2ecf20Sopenharmony_ci#include <linux/unistd.h> 1258c2ecf20Sopenharmony_ci#include <linux/string.h> 1268c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 1278c2ecf20Sopenharmony_ci#include <linux/errno.h> 1288c2ecf20Sopenharmony_ci#include <linux/ioport.h> 1298c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1308c2ecf20Sopenharmony_ci#include <linux/capability.h> 1318c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 1328c2ecf20Sopenharmony_ci#include <linux/freezer.h> 1338c2ecf20Sopenharmony_ci#include <linux/delay.h> 1348c2ecf20Sopenharmony_ci#include <linux/timer.h> 1358c2ecf20Sopenharmony_ci#include <linux/list.h> 1368c2ecf20Sopenharmony_ci#include <linux/init.h> 1378c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 1388c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 1398c2ecf20Sopenharmony_ci#include <linux/inet.h> 1408c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 1418c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 1428c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 1438c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 1448c2ecf20Sopenharmony_ci#include <linux/in.h> 1458c2ecf20Sopenharmony_ci#include <linux/ip.h> 1468c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 1478c2ecf20Sopenharmony_ci#include <linux/udp.h> 1488c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 1498c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 1508c2ecf20Sopenharmony_ci#include <linux/wait.h> 1518c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 1528c2ecf20Sopenharmony_ci#include <linux/kthread.h> 1538c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 1548c2ecf20Sopenharmony_ci#include <linux/mmzone.h> 1558c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 1568c2ecf20Sopenharmony_ci#include <net/checksum.h> 1578c2ecf20Sopenharmony_ci#include <net/ipv6.h> 1588c2ecf20Sopenharmony_ci#include <net/udp.h> 1598c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 1608c2ecf20Sopenharmony_ci#include <net/addrconf.h> 1618c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 1628c2ecf20Sopenharmony_ci#include <net/xfrm.h> 1638c2ecf20Sopenharmony_ci#endif 1648c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 1658c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 1668c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 1678c2ecf20Sopenharmony_ci#include <linux/bitops.h> 1688c2ecf20Sopenharmony_ci#include <linux/io.h> 1698c2ecf20Sopenharmony_ci#include <linux/timex.h> 1708c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1718c2ecf20Sopenharmony_ci#include <asm/dma.h> 1728c2ecf20Sopenharmony_ci#include <asm/div64.h> /* do_div */ 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define VERSION "2.75" 1758c2ecf20Sopenharmony_ci#define IP_NAME_SZ 32 1768c2ecf20Sopenharmony_ci#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ 1778c2ecf20Sopenharmony_ci#define MPLS_STACK_BOTTOM htonl(0x00000100) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define func_enter() pr_debug("entering %s\n", __func__); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define PKT_FLAGS \ 1828c2ecf20Sopenharmony_ci pf(IPV6) /* Interface in IPV6 Mode */ \ 1838c2ecf20Sopenharmony_ci pf(IPSRC_RND) /* IP-Src Random */ \ 1848c2ecf20Sopenharmony_ci pf(IPDST_RND) /* IP-Dst Random */ \ 1858c2ecf20Sopenharmony_ci pf(TXSIZE_RND) /* Transmit size is random */ \ 1868c2ecf20Sopenharmony_ci pf(UDPSRC_RND) /* UDP-Src Random */ \ 1878c2ecf20Sopenharmony_ci pf(UDPDST_RND) /* UDP-Dst Random */ \ 1888c2ecf20Sopenharmony_ci pf(UDPCSUM) /* Include UDP checksum */ \ 1898c2ecf20Sopenharmony_ci pf(NO_TIMESTAMP) /* Don't timestamp packets (default TS) */ \ 1908c2ecf20Sopenharmony_ci pf(MPLS_RND) /* Random MPLS labels */ \ 1918c2ecf20Sopenharmony_ci pf(QUEUE_MAP_RND) /* queue map Random */ \ 1928c2ecf20Sopenharmony_ci pf(QUEUE_MAP_CPU) /* queue map mirrors smp_processor_id() */ \ 1938c2ecf20Sopenharmony_ci pf(FLOW_SEQ) /* Sequential flows */ \ 1948c2ecf20Sopenharmony_ci pf(IPSEC) /* ipsec on for flows */ \ 1958c2ecf20Sopenharmony_ci pf(MACSRC_RND) /* MAC-Src Random */ \ 1968c2ecf20Sopenharmony_ci pf(MACDST_RND) /* MAC-Dst Random */ \ 1978c2ecf20Sopenharmony_ci pf(VID_RND) /* Random VLAN ID */ \ 1988c2ecf20Sopenharmony_ci pf(SVID_RND) /* Random SVLAN ID */ \ 1998c2ecf20Sopenharmony_ci pf(NODE) /* Node memory alloc*/ \ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define pf(flag) flag##_SHIFT, 2028c2ecf20Sopenharmony_cienum pkt_flags { 2038c2ecf20Sopenharmony_ci PKT_FLAGS 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci#undef pf 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* Device flag bits */ 2088c2ecf20Sopenharmony_ci#define pf(flag) static const __u32 F_##flag = (1<<flag##_SHIFT); 2098c2ecf20Sopenharmony_ciPKT_FLAGS 2108c2ecf20Sopenharmony_ci#undef pf 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#define pf(flag) __stringify(flag), 2138c2ecf20Sopenharmony_cistatic char *pkt_flag_names[] = { 2148c2ecf20Sopenharmony_ci PKT_FLAGS 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci#undef pf 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#define NR_PKT_FLAGS ARRAY_SIZE(pkt_flag_names) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* Thread control flag bits */ 2218c2ecf20Sopenharmony_ci#define T_STOP (1<<0) /* Stop run */ 2228c2ecf20Sopenharmony_ci#define T_RUN (1<<1) /* Start run */ 2238c2ecf20Sopenharmony_ci#define T_REMDEVALL (1<<2) /* Remove all devs */ 2248c2ecf20Sopenharmony_ci#define T_REMDEV (1<<3) /* Remove one dev */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* Xmit modes */ 2278c2ecf20Sopenharmony_ci#define M_START_XMIT 0 /* Default normal TX */ 2288c2ecf20Sopenharmony_ci#define M_NETIF_RECEIVE 1 /* Inject packets into stack */ 2298c2ecf20Sopenharmony_ci#define M_QUEUE_XMIT 2 /* Inject packet into qdisc */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* If lock -- protects updating of if_list */ 2328c2ecf20Sopenharmony_ci#define if_lock(t) mutex_lock(&(t->if_lock)); 2338c2ecf20Sopenharmony_ci#define if_unlock(t) mutex_unlock(&(t->if_lock)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Used to help with determining the pkts on receive */ 2368c2ecf20Sopenharmony_ci#define PKTGEN_MAGIC 0xbe9be955 2378c2ecf20Sopenharmony_ci#define PG_PROC_DIR "pktgen" 2388c2ecf20Sopenharmony_ci#define PGCTRL "pgctrl" 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define MAX_CFLOWS 65536 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 2438c2ecf20Sopenharmony_ci#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistruct flow_state { 2468c2ecf20Sopenharmony_ci __be32 cur_daddr; 2478c2ecf20Sopenharmony_ci int count; 2488c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 2498c2ecf20Sopenharmony_ci struct xfrm_state *x; 2508c2ecf20Sopenharmony_ci#endif 2518c2ecf20Sopenharmony_ci __u32 flags; 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* flow flag bits */ 2558c2ecf20Sopenharmony_ci#define F_INIT (1<<0) /* flow has been initialized */ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistruct pktgen_dev { 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * Try to keep frequent/infrequent used vars. separated. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci struct proc_dir_entry *entry; /* proc file */ 2628c2ecf20Sopenharmony_ci struct pktgen_thread *pg_thread;/* the owner */ 2638c2ecf20Sopenharmony_ci struct list_head list; /* chaining in the thread's run-queue */ 2648c2ecf20Sopenharmony_ci struct rcu_head rcu; /* freed by RCU */ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci int running; /* if false, the test will stop */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* If min != max, then we will either do a linear iteration, or 2698c2ecf20Sopenharmony_ci * we will do a random selection from within the range. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci __u32 flags; 2728c2ecf20Sopenharmony_ci int xmit_mode; 2738c2ecf20Sopenharmony_ci int min_pkt_size; 2748c2ecf20Sopenharmony_ci int max_pkt_size; 2758c2ecf20Sopenharmony_ci int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2768c2ecf20Sopenharmony_ci int nfrags; 2778c2ecf20Sopenharmony_ci int removal_mark; /* non-zero => the device is marked for 2788c2ecf20Sopenharmony_ci * removal by worker thread */ 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci struct page *page; 2818c2ecf20Sopenharmony_ci u64 delay; /* nano-seconds */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci __u64 count; /* Default No packets to send */ 2848c2ecf20Sopenharmony_ci __u64 sofar; /* How many pkts we've sent so far */ 2858c2ecf20Sopenharmony_ci __u64 tx_bytes; /* How many bytes we've transmitted */ 2868c2ecf20Sopenharmony_ci __u64 errors; /* Errors when trying to transmit, */ 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* runtime counters relating to clone_skb */ 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci __u32 clone_count; 2918c2ecf20Sopenharmony_ci int last_ok; /* Was last skb sent? 2928c2ecf20Sopenharmony_ci * Or a failed transmit of some sort? 2938c2ecf20Sopenharmony_ci * This will keep sequence numbers in order 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci ktime_t next_tx; 2968c2ecf20Sopenharmony_ci ktime_t started_at; 2978c2ecf20Sopenharmony_ci ktime_t stopped_at; 2988c2ecf20Sopenharmony_ci u64 idle_acc; /* nano-seconds */ 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci __u32 seq_num; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci int clone_skb; /* 3038c2ecf20Sopenharmony_ci * Use multiple SKBs during packet gen. 3048c2ecf20Sopenharmony_ci * If this number is greater than 1, then 3058c2ecf20Sopenharmony_ci * that many copies of the same packet will be 3068c2ecf20Sopenharmony_ci * sent before a new packet is allocated. 3078c2ecf20Sopenharmony_ci * If you want to send 1024 identical packets 3088c2ecf20Sopenharmony_ci * before creating a new packet, 3098c2ecf20Sopenharmony_ci * set clone_skb to 1024. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3138c2ecf20Sopenharmony_ci char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3148c2ecf20Sopenharmony_ci char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3158c2ecf20Sopenharmony_ci char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci struct in6_addr in6_saddr; 3188c2ecf20Sopenharmony_ci struct in6_addr in6_daddr; 3198c2ecf20Sopenharmony_ci struct in6_addr cur_in6_daddr; 3208c2ecf20Sopenharmony_ci struct in6_addr cur_in6_saddr; 3218c2ecf20Sopenharmony_ci /* For ranges */ 3228c2ecf20Sopenharmony_ci struct in6_addr min_in6_daddr; 3238c2ecf20Sopenharmony_ci struct in6_addr max_in6_daddr; 3248c2ecf20Sopenharmony_ci struct in6_addr min_in6_saddr; 3258c2ecf20Sopenharmony_ci struct in6_addr max_in6_saddr; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* If we're doing ranges, random or incremental, then this 3288c2ecf20Sopenharmony_ci * defines the min/max for those ranges. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci __be32 saddr_min; /* inclusive, source IP address */ 3318c2ecf20Sopenharmony_ci __be32 saddr_max; /* exclusive, source IP address */ 3328c2ecf20Sopenharmony_ci __be32 daddr_min; /* inclusive, dest IP address */ 3338c2ecf20Sopenharmony_ci __be32 daddr_max; /* exclusive, dest IP address */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci __u16 udp_src_min; /* inclusive, source UDP port */ 3368c2ecf20Sopenharmony_ci __u16 udp_src_max; /* exclusive, source UDP port */ 3378c2ecf20Sopenharmony_ci __u16 udp_dst_min; /* inclusive, dest UDP port */ 3388c2ecf20Sopenharmony_ci __u16 udp_dst_max; /* exclusive, dest UDP port */ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* DSCP + ECN */ 3418c2ecf20Sopenharmony_ci __u8 tos; /* six MSB of (former) IPv4 TOS 3428c2ecf20Sopenharmony_ci are for dscp codepoint */ 3438c2ecf20Sopenharmony_ci __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 3448c2ecf20Sopenharmony_ci (see RFC 3260, sec. 4) */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* MPLS */ 3478c2ecf20Sopenharmony_ci unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */ 3488c2ecf20Sopenharmony_ci __be32 labels[MAX_MPLS_LABELS]; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 3518c2ecf20Sopenharmony_ci __u8 vlan_p; 3528c2ecf20Sopenharmony_ci __u8 vlan_cfi; 3538c2ecf20Sopenharmony_ci __u16 vlan_id; /* 0xffff means no vlan tag */ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci __u8 svlan_p; 3568c2ecf20Sopenharmony_ci __u8 svlan_cfi; 3578c2ecf20Sopenharmony_ci __u16 svlan_id; /* 0xffff means no svlan tag */ 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci __u32 src_mac_count; /* How many MACs to iterate through */ 3608c2ecf20Sopenharmony_ci __u32 dst_mac_count; /* How many MACs to iterate through */ 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci unsigned char dst_mac[ETH_ALEN]; 3638c2ecf20Sopenharmony_ci unsigned char src_mac[ETH_ALEN]; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci __u32 cur_dst_mac_offset; 3668c2ecf20Sopenharmony_ci __u32 cur_src_mac_offset; 3678c2ecf20Sopenharmony_ci __be32 cur_saddr; 3688c2ecf20Sopenharmony_ci __be32 cur_daddr; 3698c2ecf20Sopenharmony_ci __u16 ip_id; 3708c2ecf20Sopenharmony_ci __u16 cur_udp_dst; 3718c2ecf20Sopenharmony_ci __u16 cur_udp_src; 3728c2ecf20Sopenharmony_ci __u16 cur_queue_map; 3738c2ecf20Sopenharmony_ci __u32 cur_pkt_size; 3748c2ecf20Sopenharmony_ci __u32 last_pkt_size; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci __u8 hh[14]; 3778c2ecf20Sopenharmony_ci /* = { 3788c2ecf20Sopenharmony_ci 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci We fill in SRC address later 3818c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3828c2ecf20Sopenharmony_ci 0x08, 0x00 3838c2ecf20Sopenharmony_ci }; 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci __u16 pad; /* pad out the hh struct to an even 16 bytes */ 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci struct sk_buff *skb; /* skb we are to transmit next, used for when we 3888c2ecf20Sopenharmony_ci * are transmitting the same one multiple times 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci struct net_device *odev; /* The out-going device. 3918c2ecf20Sopenharmony_ci * Note that the device should have it's 3928c2ecf20Sopenharmony_ci * pg_info pointer pointing back to this 3938c2ecf20Sopenharmony_ci * device. 3948c2ecf20Sopenharmony_ci * Set when the user specifies the out-going 3958c2ecf20Sopenharmony_ci * device name (not when the inject is 3968c2ecf20Sopenharmony_ci * started as it used to do.) 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci char odevname[32]; 3998c2ecf20Sopenharmony_ci struct flow_state *flows; 4008c2ecf20Sopenharmony_ci unsigned int cflows; /* Concurrent flows (config) */ 4018c2ecf20Sopenharmony_ci unsigned int lflow; /* Flow length (config) */ 4028c2ecf20Sopenharmony_ci unsigned int nflows; /* accumulated flows (stats) */ 4038c2ecf20Sopenharmony_ci unsigned int curfl; /* current sequenced flow (state)*/ 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci u16 queue_map_min; 4068c2ecf20Sopenharmony_ci u16 queue_map_max; 4078c2ecf20Sopenharmony_ci __u32 skb_priority; /* skb priority field */ 4088c2ecf20Sopenharmony_ci unsigned int burst; /* number of duplicated packets to burst */ 4098c2ecf20Sopenharmony_ci int node; /* Memory node */ 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 4128c2ecf20Sopenharmony_ci __u8 ipsmode; /* IPSEC mode (config) */ 4138c2ecf20Sopenharmony_ci __u8 ipsproto; /* IPSEC type (config) */ 4148c2ecf20Sopenharmony_ci __u32 spi; 4158c2ecf20Sopenharmony_ci struct xfrm_dst xdst; 4168c2ecf20Sopenharmony_ci struct dst_ops dstops; 4178c2ecf20Sopenharmony_ci#endif 4188c2ecf20Sopenharmony_ci char result[512]; 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistruct pktgen_hdr { 4228c2ecf20Sopenharmony_ci __be32 pgh_magic; 4238c2ecf20Sopenharmony_ci __be32 seq_num; 4248c2ecf20Sopenharmony_ci __be32 tv_sec; 4258c2ecf20Sopenharmony_ci __be32 tv_usec; 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic unsigned int pg_net_id __read_mostly; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistruct pktgen_net { 4328c2ecf20Sopenharmony_ci struct net *net; 4338c2ecf20Sopenharmony_ci struct proc_dir_entry *proc_dir; 4348c2ecf20Sopenharmony_ci struct list_head pktgen_threads; 4358c2ecf20Sopenharmony_ci bool pktgen_exiting; 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistruct pktgen_thread { 4398c2ecf20Sopenharmony_ci struct mutex if_lock; /* for list of devices */ 4408c2ecf20Sopenharmony_ci struct list_head if_list; /* All device here */ 4418c2ecf20Sopenharmony_ci struct list_head th_list; 4428c2ecf20Sopenharmony_ci struct task_struct *tsk; 4438c2ecf20Sopenharmony_ci char result[512]; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Field for thread to receive "posted" events terminate, 4468c2ecf20Sopenharmony_ci stop ifs etc. */ 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci u32 control; 4498c2ecf20Sopenharmony_ci int cpu; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci wait_queue_head_t queue; 4528c2ecf20Sopenharmony_ci struct completion start_done; 4538c2ecf20Sopenharmony_ci struct pktgen_net *net; 4548c2ecf20Sopenharmony_ci}; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci#define REMOVE 1 4578c2ecf20Sopenharmony_ci#define FIND 0 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic const char version[] = 4608c2ecf20Sopenharmony_ci "Packet Generator for packet performance testing. " 4618c2ecf20Sopenharmony_ci "Version: " VERSION "\n"; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4648c2ecf20Sopenharmony_cistatic int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 4658c2ecf20Sopenharmony_cistatic struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4668c2ecf20Sopenharmony_ci const char *ifname, bool exact); 4678c2ecf20Sopenharmony_cistatic int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4688c2ecf20Sopenharmony_cistatic void pktgen_run_all_threads(struct pktgen_net *pn); 4698c2ecf20Sopenharmony_cistatic void pktgen_reset_all_threads(struct pktgen_net *pn); 4708c2ecf20Sopenharmony_cistatic void pktgen_stop_all_threads_ifs(struct pktgen_net *pn); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void pktgen_stop(struct pktgen_thread *t); 4738c2ecf20Sopenharmony_cistatic void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* Module parameters, defaults. */ 4768c2ecf20Sopenharmony_cistatic int pg_count_d __read_mostly = 1000; 4778c2ecf20Sopenharmony_cistatic int pg_delay_d __read_mostly; 4788c2ecf20Sopenharmony_cistatic int pg_clone_skb_d __read_mostly; 4798c2ecf20Sopenharmony_cistatic int debug __read_mostly; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pktgen_thread_lock); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic struct notifier_block pktgen_notifier_block = { 4848c2ecf20Sopenharmony_ci .notifier_call = pktgen_device_event, 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/* 4888c2ecf20Sopenharmony_ci * /proc handling functions 4898c2ecf20Sopenharmony_ci * 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int pgctrl_show(struct seq_file *seq, void *v) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci seq_puts(seq, version); 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic ssize_t pgctrl_write(struct file *file, const char __user *buf, 4998c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci char data[128]; 5028c2ecf20Sopenharmony_ci struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 5058c2ecf20Sopenharmony_ci return -EPERM; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (count == 0) 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (count > sizeof(data)) 5118c2ecf20Sopenharmony_ci count = sizeof(data); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (copy_from_user(data, buf, count)) 5148c2ecf20Sopenharmony_ci return -EFAULT; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci data[count - 1] = 0; /* Strip trailing '\n' and terminate string */ 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (!strcmp(data, "stop")) 5198c2ecf20Sopenharmony_ci pktgen_stop_all_threads_ifs(pn); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci else if (!strcmp(data, "start")) 5228c2ecf20Sopenharmony_ci pktgen_run_all_threads(pn); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci else if (!strcmp(data, "reset")) 5258c2ecf20Sopenharmony_ci pktgen_reset_all_threads(pn); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci else 5288c2ecf20Sopenharmony_ci return -EINVAL; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return count; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic int pgctrl_open(struct inode *inode, struct file *file) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci return single_open(file, pgctrl_show, PDE_DATA(inode)); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct proc_ops pktgen_proc_ops = { 5398c2ecf20Sopenharmony_ci .proc_open = pgctrl_open, 5408c2ecf20Sopenharmony_ci .proc_read = seq_read, 5418c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 5428c2ecf20Sopenharmony_ci .proc_write = pgctrl_write, 5438c2ecf20Sopenharmony_ci .proc_release = single_release, 5448c2ecf20Sopenharmony_ci}; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int pktgen_if_show(struct seq_file *seq, void *v) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci const struct pktgen_dev *pkt_dev = seq->private; 5498c2ecf20Sopenharmony_ci ktime_t stopped; 5508c2ecf20Sopenharmony_ci unsigned int i; 5518c2ecf20Sopenharmony_ci u64 idle; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci seq_printf(seq, 5548c2ecf20Sopenharmony_ci "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 5558c2ecf20Sopenharmony_ci (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 5568c2ecf20Sopenharmony_ci pkt_dev->max_pkt_size); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci seq_printf(seq, 5598c2ecf20Sopenharmony_ci " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 5608c2ecf20Sopenharmony_ci pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 5618c2ecf20Sopenharmony_ci pkt_dev->clone_skb, pkt_dev->odevname); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 5648c2ecf20Sopenharmony_ci pkt_dev->lflow); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci seq_printf(seq, 5678c2ecf20Sopenharmony_ci " queue_map_min: %u queue_map_max: %u\n", 5688c2ecf20Sopenharmony_ci pkt_dev->queue_map_min, 5698c2ecf20Sopenharmony_ci pkt_dev->queue_map_max); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (pkt_dev->skb_priority) 5728c2ecf20Sopenharmony_ci seq_printf(seq, " skb_priority: %u\n", 5738c2ecf20Sopenharmony_ci pkt_dev->skb_priority); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPV6) { 5768c2ecf20Sopenharmony_ci seq_printf(seq, 5778c2ecf20Sopenharmony_ci " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" 5788c2ecf20Sopenharmony_ci " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", 5798c2ecf20Sopenharmony_ci &pkt_dev->in6_saddr, 5808c2ecf20Sopenharmony_ci &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, 5818c2ecf20Sopenharmony_ci &pkt_dev->in6_daddr, 5828c2ecf20Sopenharmony_ci &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci seq_printf(seq, 5858c2ecf20Sopenharmony_ci " dst_min: %s dst_max: %s\n", 5868c2ecf20Sopenharmony_ci pkt_dev->dst_min, pkt_dev->dst_max); 5878c2ecf20Sopenharmony_ci seq_printf(seq, 5888c2ecf20Sopenharmony_ci " src_min: %s src_max: %s\n", 5898c2ecf20Sopenharmony_ci pkt_dev->src_min, pkt_dev->src_max); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci seq_puts(seq, " src_mac: "); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci seq_printf(seq, "%pM ", 5958c2ecf20Sopenharmony_ci is_zero_ether_addr(pkt_dev->src_mac) ? 5968c2ecf20Sopenharmony_ci pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci seq_puts(seq, "dst_mac: "); 5998c2ecf20Sopenharmony_ci seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci seq_printf(seq, 6028c2ecf20Sopenharmony_ci " udp_src_min: %d udp_src_max: %d" 6038c2ecf20Sopenharmony_ci " udp_dst_min: %d udp_dst_max: %d\n", 6048c2ecf20Sopenharmony_ci pkt_dev->udp_src_min, pkt_dev->udp_src_max, 6058c2ecf20Sopenharmony_ci pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci seq_printf(seq, 6088c2ecf20Sopenharmony_ci " src_mac_count: %d dst_mac_count: %d\n", 6098c2ecf20Sopenharmony_ci pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (pkt_dev->nr_labels) { 6128c2ecf20Sopenharmony_ci seq_puts(seq, " mpls: "); 6138c2ecf20Sopenharmony_ci for (i = 0; i < pkt_dev->nr_labels; i++) 6148c2ecf20Sopenharmony_ci seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 6158c2ecf20Sopenharmony_ci i == pkt_dev->nr_labels-1 ? "\n" : ", "); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (pkt_dev->vlan_id != 0xffff) 6198c2ecf20Sopenharmony_ci seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 6208c2ecf20Sopenharmony_ci pkt_dev->vlan_id, pkt_dev->vlan_p, 6218c2ecf20Sopenharmony_ci pkt_dev->vlan_cfi); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (pkt_dev->svlan_id != 0xffff) 6248c2ecf20Sopenharmony_ci seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 6258c2ecf20Sopenharmony_ci pkt_dev->svlan_id, pkt_dev->svlan_p, 6268c2ecf20Sopenharmony_ci pkt_dev->svlan_cfi); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (pkt_dev->tos) 6298c2ecf20Sopenharmony_ci seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (pkt_dev->traffic_class) 6328c2ecf20Sopenharmony_ci seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (pkt_dev->burst > 1) 6358c2ecf20Sopenharmony_ci seq_printf(seq, " burst: %d\n", pkt_dev->burst); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (pkt_dev->node >= 0) 6388c2ecf20Sopenharmony_ci seq_printf(seq, " node: %d\n", pkt_dev->node); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) 6418c2ecf20Sopenharmony_ci seq_puts(seq, " xmit_mode: netif_receive\n"); 6428c2ecf20Sopenharmony_ci else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) 6438c2ecf20Sopenharmony_ci seq_puts(seq, " xmit_mode: xmit_queue\n"); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci seq_puts(seq, " Flags: "); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci for (i = 0; i < NR_PKT_FLAGS; i++) { 6488c2ecf20Sopenharmony_ci if (i == FLOW_SEQ_SHIFT) 6498c2ecf20Sopenharmony_ci if (!pkt_dev->cflows) 6508c2ecf20Sopenharmony_ci continue; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (pkt_dev->flags & (1 << i)) { 6538c2ecf20Sopenharmony_ci seq_printf(seq, "%s ", pkt_flag_names[i]); 6548c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 6558c2ecf20Sopenharmony_ci if (i == IPSEC_SHIFT && pkt_dev->spi) 6568c2ecf20Sopenharmony_ci seq_printf(seq, "spi:%u ", pkt_dev->spi); 6578c2ecf20Sopenharmony_ci#endif 6588c2ecf20Sopenharmony_ci } else if (i == FLOW_SEQ_SHIFT) { 6598c2ecf20Sopenharmony_ci seq_puts(seq, "FLOW_RND "); 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci seq_puts(seq, "\n"); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* not really stopped, more like last-running-at */ 6668c2ecf20Sopenharmony_ci stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at; 6678c2ecf20Sopenharmony_ci idle = pkt_dev->idle_acc; 6688c2ecf20Sopenharmony_ci do_div(idle, NSEC_PER_USEC); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci seq_printf(seq, 6718c2ecf20Sopenharmony_ci "Current:\n pkts-sofar: %llu errors: %llu\n", 6728c2ecf20Sopenharmony_ci (unsigned long long)pkt_dev->sofar, 6738c2ecf20Sopenharmony_ci (unsigned long long)pkt_dev->errors); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci seq_printf(seq, 6768c2ecf20Sopenharmony_ci " started: %lluus stopped: %lluus idle: %lluus\n", 6778c2ecf20Sopenharmony_ci (unsigned long long) ktime_to_us(pkt_dev->started_at), 6788c2ecf20Sopenharmony_ci (unsigned long long) ktime_to_us(stopped), 6798c2ecf20Sopenharmony_ci (unsigned long long) idle); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci seq_printf(seq, 6828c2ecf20Sopenharmony_ci " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 6838c2ecf20Sopenharmony_ci pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 6848c2ecf20Sopenharmony_ci pkt_dev->cur_src_mac_offset); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPV6) { 6878c2ecf20Sopenharmony_ci seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", 6888c2ecf20Sopenharmony_ci &pkt_dev->cur_in6_saddr, 6898c2ecf20Sopenharmony_ci &pkt_dev->cur_in6_daddr); 6908c2ecf20Sopenharmony_ci } else 6918c2ecf20Sopenharmony_ci seq_printf(seq, " cur_saddr: %pI4 cur_daddr: %pI4\n", 6928c2ecf20Sopenharmony_ci &pkt_dev->cur_saddr, &pkt_dev->cur_daddr); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 6958c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (pkt_dev->result[0]) 7028c2ecf20Sopenharmony_ci seq_printf(seq, "Result: %s\n", pkt_dev->result); 7038c2ecf20Sopenharmony_ci else 7048c2ecf20Sopenharmony_ci seq_puts(seq, "Result: Idle\n"); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 7118c2ecf20Sopenharmony_ci __u32 *num) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci int i = 0; 7148c2ecf20Sopenharmony_ci *num = 0; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci for (; i < maxlen; i++) { 7178c2ecf20Sopenharmony_ci int value; 7188c2ecf20Sopenharmony_ci char c; 7198c2ecf20Sopenharmony_ci *num <<= 4; 7208c2ecf20Sopenharmony_ci if (get_user(c, &user_buffer[i])) 7218c2ecf20Sopenharmony_ci return -EFAULT; 7228c2ecf20Sopenharmony_ci value = hex_to_bin(c); 7238c2ecf20Sopenharmony_ci if (value >= 0) 7248c2ecf20Sopenharmony_ci *num |= value; 7258c2ecf20Sopenharmony_ci else 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci return i; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic int count_trail_chars(const char __user * user_buffer, 7328c2ecf20Sopenharmony_ci unsigned int maxlen) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci int i; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci for (i = 0; i < maxlen; i++) { 7378c2ecf20Sopenharmony_ci char c; 7388c2ecf20Sopenharmony_ci if (get_user(c, &user_buffer[i])) 7398c2ecf20Sopenharmony_ci return -EFAULT; 7408c2ecf20Sopenharmony_ci switch (c) { 7418c2ecf20Sopenharmony_ci case '\"': 7428c2ecf20Sopenharmony_ci case '\n': 7438c2ecf20Sopenharmony_ci case '\r': 7448c2ecf20Sopenharmony_ci case '\t': 7458c2ecf20Sopenharmony_ci case ' ': 7468c2ecf20Sopenharmony_ci case '=': 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci default: 7498c2ecf20Sopenharmony_ci goto done; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_cidone: 7538c2ecf20Sopenharmony_ci return i; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic long num_arg(const char __user *user_buffer, unsigned long maxlen, 7578c2ecf20Sopenharmony_ci unsigned long *num) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci int i; 7608c2ecf20Sopenharmony_ci *num = 0; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci for (i = 0; i < maxlen; i++) { 7638c2ecf20Sopenharmony_ci char c; 7648c2ecf20Sopenharmony_ci if (get_user(c, &user_buffer[i])) 7658c2ecf20Sopenharmony_ci return -EFAULT; 7668c2ecf20Sopenharmony_ci if ((c >= '0') && (c <= '9')) { 7678c2ecf20Sopenharmony_ci *num *= 10; 7688c2ecf20Sopenharmony_ci *num += c - '0'; 7698c2ecf20Sopenharmony_ci } else 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci return i; 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic int strn_len(const char __user * user_buffer, unsigned int maxlen) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci int i; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci for (i = 0; i < maxlen; i++) { 7808c2ecf20Sopenharmony_ci char c; 7818c2ecf20Sopenharmony_ci if (get_user(c, &user_buffer[i])) 7828c2ecf20Sopenharmony_ci return -EFAULT; 7838c2ecf20Sopenharmony_ci switch (c) { 7848c2ecf20Sopenharmony_ci case '\"': 7858c2ecf20Sopenharmony_ci case '\n': 7868c2ecf20Sopenharmony_ci case '\r': 7878c2ecf20Sopenharmony_ci case '\t': 7888c2ecf20Sopenharmony_ci case ' ': 7898c2ecf20Sopenharmony_ci goto done_str; 7908c2ecf20Sopenharmony_ci default: 7918c2ecf20Sopenharmony_ci break; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_cidone_str: 7958c2ecf20Sopenharmony_ci return i; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci unsigned int n = 0; 8018c2ecf20Sopenharmony_ci char c; 8028c2ecf20Sopenharmony_ci ssize_t i = 0; 8038c2ecf20Sopenharmony_ci int len; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci pkt_dev->nr_labels = 0; 8068c2ecf20Sopenharmony_ci do { 8078c2ecf20Sopenharmony_ci __u32 tmp; 8088c2ecf20Sopenharmony_ci len = hex32_arg(&buffer[i], 8, &tmp); 8098c2ecf20Sopenharmony_ci if (len <= 0) 8108c2ecf20Sopenharmony_ci return len; 8118c2ecf20Sopenharmony_ci pkt_dev->labels[n] = htonl(tmp); 8128c2ecf20Sopenharmony_ci if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 8138c2ecf20Sopenharmony_ci pkt_dev->flags |= F_MPLS_RND; 8148c2ecf20Sopenharmony_ci i += len; 8158c2ecf20Sopenharmony_ci if (get_user(c, &buffer[i])) 8168c2ecf20Sopenharmony_ci return -EFAULT; 8178c2ecf20Sopenharmony_ci i++; 8188c2ecf20Sopenharmony_ci n++; 8198c2ecf20Sopenharmony_ci if (n >= MAX_MPLS_LABELS) 8208c2ecf20Sopenharmony_ci return -E2BIG; 8218c2ecf20Sopenharmony_ci } while (c == ','); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci pkt_dev->nr_labels = n; 8248c2ecf20Sopenharmony_ci return i; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic __u32 pktgen_read_flag(const char *f, bool *disable) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci __u32 i; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (f[0] == '!') { 8328c2ecf20Sopenharmony_ci *disable = true; 8338c2ecf20Sopenharmony_ci f++; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci for (i = 0; i < NR_PKT_FLAGS; i++) { 8378c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_XFRM) && i == IPSEC_SHIFT) 8388c2ecf20Sopenharmony_ci continue; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* allow only disabling ipv6 flag */ 8418c2ecf20Sopenharmony_ci if (!*disable && i == IPV6_SHIFT) 8428c2ecf20Sopenharmony_ci continue; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (strcmp(f, pkt_flag_names[i]) == 0) 8458c2ecf20Sopenharmony_ci return 1 << i; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (strcmp(f, "FLOW_RND") == 0) { 8498c2ecf20Sopenharmony_ci *disable = !*disable; 8508c2ecf20Sopenharmony_ci return F_FLOW_SEQ; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic ssize_t pktgen_if_write(struct file *file, 8578c2ecf20Sopenharmony_ci const char __user * user_buffer, size_t count, 8588c2ecf20Sopenharmony_ci loff_t * offset) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct seq_file *seq = file->private_data; 8618c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev = seq->private; 8628c2ecf20Sopenharmony_ci int i, max, len; 8638c2ecf20Sopenharmony_ci char name[16], valstr[32]; 8648c2ecf20Sopenharmony_ci unsigned long value = 0; 8658c2ecf20Sopenharmony_ci char *pg_result = NULL; 8668c2ecf20Sopenharmony_ci int tmp = 0; 8678c2ecf20Sopenharmony_ci char buf[128]; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci pg_result = &(pkt_dev->result[0]); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (count < 1) { 8728c2ecf20Sopenharmony_ci pr_warn("wrong command format\n"); 8738c2ecf20Sopenharmony_ci return -EINVAL; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci max = count; 8778c2ecf20Sopenharmony_ci tmp = count_trail_chars(user_buffer, max); 8788c2ecf20Sopenharmony_ci if (tmp < 0) { 8798c2ecf20Sopenharmony_ci pr_warn("illegal format\n"); 8808c2ecf20Sopenharmony_ci return tmp; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci i = tmp; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* Read variable name */ 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(name) - 1); 8878c2ecf20Sopenharmony_ci if (len < 0) 8888c2ecf20Sopenharmony_ci return len; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci memset(name, 0, sizeof(name)); 8918c2ecf20Sopenharmony_ci if (copy_from_user(name, &user_buffer[i], len)) 8928c2ecf20Sopenharmony_ci return -EFAULT; 8938c2ecf20Sopenharmony_ci i += len; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci max = count - i; 8968c2ecf20Sopenharmony_ci len = count_trail_chars(&user_buffer[i], max); 8978c2ecf20Sopenharmony_ci if (len < 0) 8988c2ecf20Sopenharmony_ci return len; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci i += len; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (debug) { 9038c2ecf20Sopenharmony_ci size_t copy = min_t(size_t, count + 1, 1024); 9048c2ecf20Sopenharmony_ci char *tp = strndup_user(user_buffer, copy); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (IS_ERR(tp)) 9078c2ecf20Sopenharmony_ci return PTR_ERR(tp); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci pr_debug("%s,%zu buffer -:%s:-\n", name, count, tp); 9108c2ecf20Sopenharmony_ci kfree(tp); 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!strcmp(name, "min_pkt_size")) { 9148c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 9158c2ecf20Sopenharmony_ci if (len < 0) 9168c2ecf20Sopenharmony_ci return len; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci i += len; 9198c2ecf20Sopenharmony_ci if (value < 14 + 20 + 8) 9208c2ecf20Sopenharmony_ci value = 14 + 20 + 8; 9218c2ecf20Sopenharmony_ci if (value != pkt_dev->min_pkt_size) { 9228c2ecf20Sopenharmony_ci pkt_dev->min_pkt_size = value; 9238c2ecf20Sopenharmony_ci pkt_dev->cur_pkt_size = value; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: min_pkt_size=%d", 9268c2ecf20Sopenharmony_ci pkt_dev->min_pkt_size); 9278c2ecf20Sopenharmony_ci return count; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (!strcmp(name, "max_pkt_size")) { 9318c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 9328c2ecf20Sopenharmony_ci if (len < 0) 9338c2ecf20Sopenharmony_ci return len; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci i += len; 9368c2ecf20Sopenharmony_ci if (value < 14 + 20 + 8) 9378c2ecf20Sopenharmony_ci value = 14 + 20 + 8; 9388c2ecf20Sopenharmony_ci if (value != pkt_dev->max_pkt_size) { 9398c2ecf20Sopenharmony_ci pkt_dev->max_pkt_size = value; 9408c2ecf20Sopenharmony_ci pkt_dev->cur_pkt_size = value; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: max_pkt_size=%d", 9438c2ecf20Sopenharmony_ci pkt_dev->max_pkt_size); 9448c2ecf20Sopenharmony_ci return count; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* Shortcut for min = max */ 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (!strcmp(name, "pkt_size")) { 9508c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 9518c2ecf20Sopenharmony_ci if (len < 0) 9528c2ecf20Sopenharmony_ci return len; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci i += len; 9558c2ecf20Sopenharmony_ci if (value < 14 + 20 + 8) 9568c2ecf20Sopenharmony_ci value = 14 + 20 + 8; 9578c2ecf20Sopenharmony_ci if (value != pkt_dev->min_pkt_size) { 9588c2ecf20Sopenharmony_ci pkt_dev->min_pkt_size = value; 9598c2ecf20Sopenharmony_ci pkt_dev->max_pkt_size = value; 9608c2ecf20Sopenharmony_ci pkt_dev->cur_pkt_size = value; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: pkt_size=%d", pkt_dev->min_pkt_size); 9638c2ecf20Sopenharmony_ci return count; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (!strcmp(name, "debug")) { 9678c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 9688c2ecf20Sopenharmony_ci if (len < 0) 9698c2ecf20Sopenharmony_ci return len; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci i += len; 9728c2ecf20Sopenharmony_ci debug = value; 9738c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: debug=%u", debug); 9748c2ecf20Sopenharmony_ci return count; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (!strcmp(name, "frags")) { 9788c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 9798c2ecf20Sopenharmony_ci if (len < 0) 9808c2ecf20Sopenharmony_ci return len; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci i += len; 9838c2ecf20Sopenharmony_ci pkt_dev->nfrags = value; 9848c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: frags=%d", pkt_dev->nfrags); 9858c2ecf20Sopenharmony_ci return count; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci if (!strcmp(name, "delay")) { 9888c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 9898c2ecf20Sopenharmony_ci if (len < 0) 9908c2ecf20Sopenharmony_ci return len; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci i += len; 9938c2ecf20Sopenharmony_ci if (value == 0x7FFFFFFF) 9948c2ecf20Sopenharmony_ci pkt_dev->delay = ULLONG_MAX; 9958c2ecf20Sopenharmony_ci else 9968c2ecf20Sopenharmony_ci pkt_dev->delay = (u64)value; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: delay=%llu", 9998c2ecf20Sopenharmony_ci (unsigned long long) pkt_dev->delay); 10008c2ecf20Sopenharmony_ci return count; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci if (!strcmp(name, "rate")) { 10038c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10048c2ecf20Sopenharmony_ci if (len < 0) 10058c2ecf20Sopenharmony_ci return len; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci i += len; 10088c2ecf20Sopenharmony_ci if (!value) 10098c2ecf20Sopenharmony_ci return len; 10108c2ecf20Sopenharmony_ci pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 10118c2ecf20Sopenharmony_ci if (debug) 10128c2ecf20Sopenharmony_ci pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: rate=%lu", value); 10158c2ecf20Sopenharmony_ci return count; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci if (!strcmp(name, "ratep")) { 10188c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10198c2ecf20Sopenharmony_ci if (len < 0) 10208c2ecf20Sopenharmony_ci return len; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci i += len; 10238c2ecf20Sopenharmony_ci if (!value) 10248c2ecf20Sopenharmony_ci return len; 10258c2ecf20Sopenharmony_ci pkt_dev->delay = NSEC_PER_SEC/value; 10268c2ecf20Sopenharmony_ci if (debug) 10278c2ecf20Sopenharmony_ci pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: rate=%lu", value); 10308c2ecf20Sopenharmony_ci return count; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci if (!strcmp(name, "udp_src_min")) { 10338c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10348c2ecf20Sopenharmony_ci if (len < 0) 10358c2ecf20Sopenharmony_ci return len; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci i += len; 10388c2ecf20Sopenharmony_ci if (value != pkt_dev->udp_src_min) { 10398c2ecf20Sopenharmony_ci pkt_dev->udp_src_min = value; 10408c2ecf20Sopenharmony_ci pkt_dev->cur_udp_src = value; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10438c2ecf20Sopenharmony_ci return count; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci if (!strcmp(name, "udp_dst_min")) { 10468c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10478c2ecf20Sopenharmony_ci if (len < 0) 10488c2ecf20Sopenharmony_ci return len; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci i += len; 10518c2ecf20Sopenharmony_ci if (value != pkt_dev->udp_dst_min) { 10528c2ecf20Sopenharmony_ci pkt_dev->udp_dst_min = value; 10538c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst = value; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10568c2ecf20Sopenharmony_ci return count; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci if (!strcmp(name, "udp_src_max")) { 10598c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10608c2ecf20Sopenharmony_ci if (len < 0) 10618c2ecf20Sopenharmony_ci return len; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci i += len; 10648c2ecf20Sopenharmony_ci if (value != pkt_dev->udp_src_max) { 10658c2ecf20Sopenharmony_ci pkt_dev->udp_src_max = value; 10668c2ecf20Sopenharmony_ci pkt_dev->cur_udp_src = value; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10698c2ecf20Sopenharmony_ci return count; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci if (!strcmp(name, "udp_dst_max")) { 10728c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10738c2ecf20Sopenharmony_ci if (len < 0) 10748c2ecf20Sopenharmony_ci return len; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci i += len; 10778c2ecf20Sopenharmony_ci if (value != pkt_dev->udp_dst_max) { 10788c2ecf20Sopenharmony_ci pkt_dev->udp_dst_max = value; 10798c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst = value; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10828c2ecf20Sopenharmony_ci return count; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci if (!strcmp(name, "clone_skb")) { 10858c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 10868c2ecf20Sopenharmony_ci if (len < 0) 10878c2ecf20Sopenharmony_ci return len; 10888c2ecf20Sopenharmony_ci if ((value > 0) && 10898c2ecf20Sopenharmony_ci ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) || 10908c2ecf20Sopenharmony_ci !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) 10918c2ecf20Sopenharmony_ci return -ENOTSUPP; 10928c2ecf20Sopenharmony_ci i += len; 10938c2ecf20Sopenharmony_ci pkt_dev->clone_skb = value; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10968c2ecf20Sopenharmony_ci return count; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci if (!strcmp(name, "count")) { 10998c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 11008c2ecf20Sopenharmony_ci if (len < 0) 11018c2ecf20Sopenharmony_ci return len; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci i += len; 11048c2ecf20Sopenharmony_ci pkt_dev->count = value; 11058c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: count=%llu", 11068c2ecf20Sopenharmony_ci (unsigned long long)pkt_dev->count); 11078c2ecf20Sopenharmony_ci return count; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci if (!strcmp(name, "src_mac_count")) { 11108c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 11118c2ecf20Sopenharmony_ci if (len < 0) 11128c2ecf20Sopenharmony_ci return len; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci i += len; 11158c2ecf20Sopenharmony_ci if (pkt_dev->src_mac_count != value) { 11168c2ecf20Sopenharmony_ci pkt_dev->src_mac_count = value; 11178c2ecf20Sopenharmony_ci pkt_dev->cur_src_mac_offset = 0; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: src_mac_count=%d", 11208c2ecf20Sopenharmony_ci pkt_dev->src_mac_count); 11218c2ecf20Sopenharmony_ci return count; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci if (!strcmp(name, "dst_mac_count")) { 11248c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 11258c2ecf20Sopenharmony_ci if (len < 0) 11268c2ecf20Sopenharmony_ci return len; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci i += len; 11298c2ecf20Sopenharmony_ci if (pkt_dev->dst_mac_count != value) { 11308c2ecf20Sopenharmony_ci pkt_dev->dst_mac_count = value; 11318c2ecf20Sopenharmony_ci pkt_dev->cur_dst_mac_offset = 0; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dst_mac_count=%d", 11348c2ecf20Sopenharmony_ci pkt_dev->dst_mac_count); 11358c2ecf20Sopenharmony_ci return count; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci if (!strcmp(name, "burst")) { 11388c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 11398c2ecf20Sopenharmony_ci if (len < 0) 11408c2ecf20Sopenharmony_ci return len; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci i += len; 11438c2ecf20Sopenharmony_ci if ((value > 1) && 11448c2ecf20Sopenharmony_ci ((pkt_dev->xmit_mode == M_QUEUE_XMIT) || 11458c2ecf20Sopenharmony_ci ((pkt_dev->xmit_mode == M_START_XMIT) && 11468c2ecf20Sopenharmony_ci (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))))) 11478c2ecf20Sopenharmony_ci return -ENOTSUPP; 11488c2ecf20Sopenharmony_ci pkt_dev->burst = value < 1 ? 1 : value; 11498c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: burst=%u", pkt_dev->burst); 11508c2ecf20Sopenharmony_ci return count; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci if (!strcmp(name, "node")) { 11538c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 11548c2ecf20Sopenharmony_ci if (len < 0) 11558c2ecf20Sopenharmony_ci return len; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci i += len; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (node_possible(value)) { 11608c2ecf20Sopenharmony_ci pkt_dev->node = value; 11618c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: node=%d", pkt_dev->node); 11628c2ecf20Sopenharmony_ci if (pkt_dev->page) { 11638c2ecf20Sopenharmony_ci put_page(pkt_dev->page); 11648c2ecf20Sopenharmony_ci pkt_dev->page = NULL; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci else 11688c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: node not possible"); 11698c2ecf20Sopenharmony_ci return count; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci if (!strcmp(name, "xmit_mode")) { 11728c2ecf20Sopenharmony_ci char f[32]; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci memset(f, 0, 32); 11758c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(f) - 1); 11768c2ecf20Sopenharmony_ci if (len < 0) 11778c2ecf20Sopenharmony_ci return len; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (copy_from_user(f, &user_buffer[i], len)) 11808c2ecf20Sopenharmony_ci return -EFAULT; 11818c2ecf20Sopenharmony_ci i += len; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (strcmp(f, "start_xmit") == 0) { 11848c2ecf20Sopenharmony_ci pkt_dev->xmit_mode = M_START_XMIT; 11858c2ecf20Sopenharmony_ci } else if (strcmp(f, "netif_receive") == 0) { 11868c2ecf20Sopenharmony_ci /* clone_skb set earlier, not supported in this mode */ 11878c2ecf20Sopenharmony_ci if (pkt_dev->clone_skb > 0) 11888c2ecf20Sopenharmony_ci return -ENOTSUPP; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci pkt_dev->xmit_mode = M_NETIF_RECEIVE; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* make sure new packet is allocated every time 11938c2ecf20Sopenharmony_ci * pktgen_xmit() is called 11948c2ecf20Sopenharmony_ci */ 11958c2ecf20Sopenharmony_ci pkt_dev->last_ok = 1; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* override clone_skb if user passed default value 11988c2ecf20Sopenharmony_ci * at module loading time 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci pkt_dev->clone_skb = 0; 12018c2ecf20Sopenharmony_ci } else if (strcmp(f, "queue_xmit") == 0) { 12028c2ecf20Sopenharmony_ci pkt_dev->xmit_mode = M_QUEUE_XMIT; 12038c2ecf20Sopenharmony_ci pkt_dev->last_ok = 1; 12048c2ecf20Sopenharmony_ci } else { 12058c2ecf20Sopenharmony_ci sprintf(pg_result, 12068c2ecf20Sopenharmony_ci "xmit_mode -:%s:- unknown\nAvailable modes: %s", 12078c2ecf20Sopenharmony_ci f, "start_xmit, netif_receive\n"); 12088c2ecf20Sopenharmony_ci return count; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: xmit_mode=%s", f); 12118c2ecf20Sopenharmony_ci return count; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci if (!strcmp(name, "flag")) { 12148c2ecf20Sopenharmony_ci __u32 flag; 12158c2ecf20Sopenharmony_ci char f[32]; 12168c2ecf20Sopenharmony_ci bool disable = false; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci memset(f, 0, 32); 12198c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(f) - 1); 12208c2ecf20Sopenharmony_ci if (len < 0) 12218c2ecf20Sopenharmony_ci return len; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (copy_from_user(f, &user_buffer[i], len)) 12248c2ecf20Sopenharmony_ci return -EFAULT; 12258c2ecf20Sopenharmony_ci i += len; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci flag = pktgen_read_flag(f, &disable); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (flag) { 12308c2ecf20Sopenharmony_ci if (disable) 12318c2ecf20Sopenharmony_ci pkt_dev->flags &= ~flag; 12328c2ecf20Sopenharmony_ci else 12338c2ecf20Sopenharmony_ci pkt_dev->flags |= flag; 12348c2ecf20Sopenharmony_ci } else { 12358c2ecf20Sopenharmony_ci sprintf(pg_result, 12368c2ecf20Sopenharmony_ci "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12378c2ecf20Sopenharmony_ci f, 12388c2ecf20Sopenharmony_ci "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 12398c2ecf20Sopenharmony_ci "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, " 12408c2ecf20Sopenharmony_ci "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, " 12418c2ecf20Sopenharmony_ci "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, " 12428c2ecf20Sopenharmony_ci "NO_TIMESTAMP, " 12438c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 12448c2ecf20Sopenharmony_ci "IPSEC, " 12458c2ecf20Sopenharmony_ci#endif 12468c2ecf20Sopenharmony_ci "NODE_ALLOC\n"); 12478c2ecf20Sopenharmony_ci return count; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12508c2ecf20Sopenharmony_ci return count; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12538c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 12548c2ecf20Sopenharmony_ci if (len < 0) 12558c2ecf20Sopenharmony_ci return len; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 12588c2ecf20Sopenharmony_ci return -EFAULT; 12598c2ecf20Sopenharmony_ci buf[len] = 0; 12608c2ecf20Sopenharmony_ci if (strcmp(buf, pkt_dev->dst_min) != 0) { 12618c2ecf20Sopenharmony_ci memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12628c2ecf20Sopenharmony_ci strcpy(pkt_dev->dst_min, buf); 12638c2ecf20Sopenharmony_ci pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12648c2ecf20Sopenharmony_ci pkt_dev->cur_daddr = pkt_dev->daddr_min; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci if (debug) 12678c2ecf20Sopenharmony_ci pr_debug("dst_min set to: %s\n", pkt_dev->dst_min); 12688c2ecf20Sopenharmony_ci i += len; 12698c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12708c2ecf20Sopenharmony_ci return count; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci if (!strcmp(name, "dst_max")) { 12738c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 12748c2ecf20Sopenharmony_ci if (len < 0) 12758c2ecf20Sopenharmony_ci return len; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 12788c2ecf20Sopenharmony_ci return -EFAULT; 12798c2ecf20Sopenharmony_ci buf[len] = 0; 12808c2ecf20Sopenharmony_ci if (strcmp(buf, pkt_dev->dst_max) != 0) { 12818c2ecf20Sopenharmony_ci memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 12828c2ecf20Sopenharmony_ci strcpy(pkt_dev->dst_max, buf); 12838c2ecf20Sopenharmony_ci pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12848c2ecf20Sopenharmony_ci pkt_dev->cur_daddr = pkt_dev->daddr_max; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci if (debug) 12878c2ecf20Sopenharmony_ci pr_debug("dst_max set to: %s\n", pkt_dev->dst_max); 12888c2ecf20Sopenharmony_ci i += len; 12898c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12908c2ecf20Sopenharmony_ci return count; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci if (!strcmp(name, "dst6")) { 12938c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(buf) - 1); 12948c2ecf20Sopenharmony_ci if (len < 0) 12958c2ecf20Sopenharmony_ci return len; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci pkt_dev->flags |= F_IPV6; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 13008c2ecf20Sopenharmony_ci return -EFAULT; 13018c2ecf20Sopenharmony_ci buf[len] = 0; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL); 13048c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (debug) 13098c2ecf20Sopenharmony_ci pr_debug("dst6 set to: %s\n", buf); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci i += len; 13128c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dst6=%s", buf); 13138c2ecf20Sopenharmony_ci return count; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci if (!strcmp(name, "dst6_min")) { 13168c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(buf) - 1); 13178c2ecf20Sopenharmony_ci if (len < 0) 13188c2ecf20Sopenharmony_ci return len; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci pkt_dev->flags |= F_IPV6; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 13238c2ecf20Sopenharmony_ci return -EFAULT; 13248c2ecf20Sopenharmony_ci buf[len] = 0; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL); 13278c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr; 13308c2ecf20Sopenharmony_ci if (debug) 13318c2ecf20Sopenharmony_ci pr_debug("dst6_min set to: %s\n", buf); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci i += len; 13348c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dst6_min=%s", buf); 13358c2ecf20Sopenharmony_ci return count; 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci if (!strcmp(name, "dst6_max")) { 13388c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(buf) - 1); 13398c2ecf20Sopenharmony_ci if (len < 0) 13408c2ecf20Sopenharmony_ci return len; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci pkt_dev->flags |= F_IPV6; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 13458c2ecf20Sopenharmony_ci return -EFAULT; 13468c2ecf20Sopenharmony_ci buf[len] = 0; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL); 13498c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (debug) 13528c2ecf20Sopenharmony_ci pr_debug("dst6_max set to: %s\n", buf); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci i += len; 13558c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dst6_max=%s", buf); 13568c2ecf20Sopenharmony_ci return count; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci if (!strcmp(name, "src6")) { 13598c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(buf) - 1); 13608c2ecf20Sopenharmony_ci if (len < 0) 13618c2ecf20Sopenharmony_ci return len; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci pkt_dev->flags |= F_IPV6; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 13668c2ecf20Sopenharmony_ci return -EFAULT; 13678c2ecf20Sopenharmony_ci buf[len] = 0; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL); 13708c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci if (debug) 13758c2ecf20Sopenharmony_ci pr_debug("src6 set to: %s\n", buf); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci i += len; 13788c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: src6=%s", buf); 13798c2ecf20Sopenharmony_ci return count; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci if (!strcmp(name, "src_min")) { 13828c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 13838c2ecf20Sopenharmony_ci if (len < 0) 13848c2ecf20Sopenharmony_ci return len; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 13878c2ecf20Sopenharmony_ci return -EFAULT; 13888c2ecf20Sopenharmony_ci buf[len] = 0; 13898c2ecf20Sopenharmony_ci if (strcmp(buf, pkt_dev->src_min) != 0) { 13908c2ecf20Sopenharmony_ci memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 13918c2ecf20Sopenharmony_ci strcpy(pkt_dev->src_min, buf); 13928c2ecf20Sopenharmony_ci pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13938c2ecf20Sopenharmony_ci pkt_dev->cur_saddr = pkt_dev->saddr_min; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci if (debug) 13968c2ecf20Sopenharmony_ci pr_debug("src_min set to: %s\n", pkt_dev->src_min); 13978c2ecf20Sopenharmony_ci i += len; 13988c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 13998c2ecf20Sopenharmony_ci return count; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci if (!strcmp(name, "src_max")) { 14028c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 14038c2ecf20Sopenharmony_ci if (len < 0) 14048c2ecf20Sopenharmony_ci return len; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (copy_from_user(buf, &user_buffer[i], len)) 14078c2ecf20Sopenharmony_ci return -EFAULT; 14088c2ecf20Sopenharmony_ci buf[len] = 0; 14098c2ecf20Sopenharmony_ci if (strcmp(buf, pkt_dev->src_max) != 0) { 14108c2ecf20Sopenharmony_ci memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14118c2ecf20Sopenharmony_ci strcpy(pkt_dev->src_max, buf); 14128c2ecf20Sopenharmony_ci pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14138c2ecf20Sopenharmony_ci pkt_dev->cur_saddr = pkt_dev->saddr_max; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci if (debug) 14168c2ecf20Sopenharmony_ci pr_debug("src_max set to: %s\n", pkt_dev->src_max); 14178c2ecf20Sopenharmony_ci i += len; 14188c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14198c2ecf20Sopenharmony_ci return count; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci if (!strcmp(name, "dst_mac")) { 14228c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 14238c2ecf20Sopenharmony_ci if (len < 0) 14248c2ecf20Sopenharmony_ci return len; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci memset(valstr, 0, sizeof(valstr)); 14278c2ecf20Sopenharmony_ci if (copy_from_user(valstr, &user_buffer[i], len)) 14288c2ecf20Sopenharmony_ci return -EFAULT; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (!mac_pton(valstr, pkt_dev->dst_mac)) 14318c2ecf20Sopenharmony_ci return -EINVAL; 14328c2ecf20Sopenharmony_ci /* Set up Dest MAC */ 14338c2ecf20Sopenharmony_ci ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); 14368c2ecf20Sopenharmony_ci return count; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci if (!strcmp(name, "src_mac")) { 14398c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 14408c2ecf20Sopenharmony_ci if (len < 0) 14418c2ecf20Sopenharmony_ci return len; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci memset(valstr, 0, sizeof(valstr)); 14448c2ecf20Sopenharmony_ci if (copy_from_user(valstr, &user_buffer[i], len)) 14458c2ecf20Sopenharmony_ci return -EFAULT; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (!mac_pton(valstr, pkt_dev->src_mac)) 14488c2ecf20Sopenharmony_ci return -EINVAL; 14498c2ecf20Sopenharmony_ci /* Set up Src MAC */ 14508c2ecf20Sopenharmony_ci ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); 14538c2ecf20Sopenharmony_ci return count; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (!strcmp(name, "clear_counters")) { 14578c2ecf20Sopenharmony_ci pktgen_clear_counters(pkt_dev); 14588c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: Clearing counters.\n"); 14598c2ecf20Sopenharmony_ci return count; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (!strcmp(name, "flows")) { 14638c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 14648c2ecf20Sopenharmony_ci if (len < 0) 14658c2ecf20Sopenharmony_ci return len; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci i += len; 14688c2ecf20Sopenharmony_ci if (value > MAX_CFLOWS) 14698c2ecf20Sopenharmony_ci value = MAX_CFLOWS; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci pkt_dev->cflows = value; 14728c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 14738c2ecf20Sopenharmony_ci return count; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 14768c2ecf20Sopenharmony_ci if (!strcmp(name, "spi")) { 14778c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 14788c2ecf20Sopenharmony_ci if (len < 0) 14798c2ecf20Sopenharmony_ci return len; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci i += len; 14828c2ecf20Sopenharmony_ci pkt_dev->spi = value; 14838c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); 14848c2ecf20Sopenharmony_ci return count; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci#endif 14878c2ecf20Sopenharmony_ci if (!strcmp(name, "flowlen")) { 14888c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 10, &value); 14898c2ecf20Sopenharmony_ci if (len < 0) 14908c2ecf20Sopenharmony_ci return len; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci i += len; 14938c2ecf20Sopenharmony_ci pkt_dev->lflow = value; 14948c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 14958c2ecf20Sopenharmony_ci return count; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (!strcmp(name, "queue_map_min")) { 14998c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 5, &value); 15008c2ecf20Sopenharmony_ci if (len < 0) 15018c2ecf20Sopenharmony_ci return len; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci i += len; 15048c2ecf20Sopenharmony_ci pkt_dev->queue_map_min = value; 15058c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 15068c2ecf20Sopenharmony_ci return count; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (!strcmp(name, "queue_map_max")) { 15108c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 5, &value); 15118c2ecf20Sopenharmony_ci if (len < 0) 15128c2ecf20Sopenharmony_ci return len; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci i += len; 15158c2ecf20Sopenharmony_ci pkt_dev->queue_map_max = value; 15168c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 15178c2ecf20Sopenharmony_ci return count; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (!strcmp(name, "mpls")) { 15218c2ecf20Sopenharmony_ci unsigned int n, cnt; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci len = get_labels(&user_buffer[i], pkt_dev); 15248c2ecf20Sopenharmony_ci if (len < 0) 15258c2ecf20Sopenharmony_ci return len; 15268c2ecf20Sopenharmony_ci i += len; 15278c2ecf20Sopenharmony_ci cnt = sprintf(pg_result, "OK: mpls="); 15288c2ecf20Sopenharmony_ci for (n = 0; n < pkt_dev->nr_labels; n++) 15298c2ecf20Sopenharmony_ci cnt += sprintf(pg_result + cnt, 15308c2ecf20Sopenharmony_ci "%08x%s", ntohl(pkt_dev->labels[n]), 15318c2ecf20Sopenharmony_ci n == pkt_dev->nr_labels-1 ? "" : ","); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 15348c2ecf20Sopenharmony_ci pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 15358c2ecf20Sopenharmony_ci pkt_dev->svlan_id = 0xffff; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (debug) 15388c2ecf20Sopenharmony_ci pr_debug("VLAN/SVLAN auto turned off\n"); 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci return count; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (!strcmp(name, "vlan_id")) { 15448c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 4, &value); 15458c2ecf20Sopenharmony_ci if (len < 0) 15468c2ecf20Sopenharmony_ci return len; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci i += len; 15498c2ecf20Sopenharmony_ci if (value <= 4095) { 15508c2ecf20Sopenharmony_ci pkt_dev->vlan_id = value; /* turn on VLAN */ 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (debug) 15538c2ecf20Sopenharmony_ci pr_debug("VLAN turned on\n"); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (debug && pkt_dev->nr_labels) 15568c2ecf20Sopenharmony_ci pr_debug("MPLS auto turned off\n"); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci pkt_dev->nr_labels = 0; /* turn off MPLS */ 15598c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 15608c2ecf20Sopenharmony_ci } else { 15618c2ecf20Sopenharmony_ci pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 15628c2ecf20Sopenharmony_ci pkt_dev->svlan_id = 0xffff; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (debug) 15658c2ecf20Sopenharmony_ci pr_debug("VLAN/SVLAN turned off\n"); 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci return count; 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (!strcmp(name, "vlan_p")) { 15718c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 1, &value); 15728c2ecf20Sopenharmony_ci if (len < 0) 15738c2ecf20Sopenharmony_ci return len; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci i += len; 15768c2ecf20Sopenharmony_ci if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 15778c2ecf20Sopenharmony_ci pkt_dev->vlan_p = value; 15788c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 15798c2ecf20Sopenharmony_ci } else { 15808c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci return count; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (!strcmp(name, "vlan_cfi")) { 15868c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 1, &value); 15878c2ecf20Sopenharmony_ci if (len < 0) 15888c2ecf20Sopenharmony_ci return len; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci i += len; 15918c2ecf20Sopenharmony_ci if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 15928c2ecf20Sopenharmony_ci pkt_dev->vlan_cfi = value; 15938c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 15948c2ecf20Sopenharmony_ci } else { 15958c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci return count; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (!strcmp(name, "svlan_id")) { 16018c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 4, &value); 16028c2ecf20Sopenharmony_ci if (len < 0) 16038c2ecf20Sopenharmony_ci return len; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci i += len; 16068c2ecf20Sopenharmony_ci if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 16078c2ecf20Sopenharmony_ci pkt_dev->svlan_id = value; /* turn on SVLAN */ 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (debug) 16108c2ecf20Sopenharmony_ci pr_debug("SVLAN turned on\n"); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (debug && pkt_dev->nr_labels) 16138c2ecf20Sopenharmony_ci pr_debug("MPLS auto turned off\n"); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci pkt_dev->nr_labels = 0; /* turn off MPLS */ 16168c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 16178c2ecf20Sopenharmony_ci } else { 16188c2ecf20Sopenharmony_ci pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 16198c2ecf20Sopenharmony_ci pkt_dev->svlan_id = 0xffff; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (debug) 16228c2ecf20Sopenharmony_ci pr_debug("VLAN/SVLAN turned off\n"); 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci return count; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (!strcmp(name, "svlan_p")) { 16288c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 1, &value); 16298c2ecf20Sopenharmony_ci if (len < 0) 16308c2ecf20Sopenharmony_ci return len; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci i += len; 16338c2ecf20Sopenharmony_ci if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 16348c2ecf20Sopenharmony_ci pkt_dev->svlan_p = value; 16358c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 16368c2ecf20Sopenharmony_ci } else { 16378c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci return count; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (!strcmp(name, "svlan_cfi")) { 16438c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 1, &value); 16448c2ecf20Sopenharmony_ci if (len < 0) 16458c2ecf20Sopenharmony_ci return len; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci i += len; 16488c2ecf20Sopenharmony_ci if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 16498c2ecf20Sopenharmony_ci pkt_dev->svlan_cfi = value; 16508c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 16518c2ecf20Sopenharmony_ci } else { 16528c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci return count; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (!strcmp(name, "tos")) { 16588c2ecf20Sopenharmony_ci __u32 tmp_value = 0; 16598c2ecf20Sopenharmony_ci len = hex32_arg(&user_buffer[i], 2, &tmp_value); 16608c2ecf20Sopenharmony_ci if (len < 0) 16618c2ecf20Sopenharmony_ci return len; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci i += len; 16648c2ecf20Sopenharmony_ci if (len == 2) { 16658c2ecf20Sopenharmony_ci pkt_dev->tos = tmp_value; 16668c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16678c2ecf20Sopenharmony_ci } else { 16688c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: tos must be 00-ff"); 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci return count; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (!strcmp(name, "traffic_class")) { 16748c2ecf20Sopenharmony_ci __u32 tmp_value = 0; 16758c2ecf20Sopenharmony_ci len = hex32_arg(&user_buffer[i], 2, &tmp_value); 16768c2ecf20Sopenharmony_ci if (len < 0) 16778c2ecf20Sopenharmony_ci return len; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci i += len; 16808c2ecf20Sopenharmony_ci if (len == 2) { 16818c2ecf20Sopenharmony_ci pkt_dev->traffic_class = tmp_value; 16828c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 16838c2ecf20Sopenharmony_ci } else { 16848c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci return count; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (!strcmp(name, "skb_priority")) { 16908c2ecf20Sopenharmony_ci len = num_arg(&user_buffer[i], 9, &value); 16918c2ecf20Sopenharmony_ci if (len < 0) 16928c2ecf20Sopenharmony_ci return len; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci i += len; 16958c2ecf20Sopenharmony_ci pkt_dev->skb_priority = value; 16968c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: skb_priority=%i", 16978c2ecf20Sopenharmony_ci pkt_dev->skb_priority); 16988c2ecf20Sopenharmony_ci return count; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 17028c2ecf20Sopenharmony_ci return -EINVAL; 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic int pktgen_if_open(struct inode *inode, struct file *file) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci return single_open(file, pktgen_if_show, PDE_DATA(inode)); 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_cistatic const struct proc_ops pktgen_if_proc_ops = { 17118c2ecf20Sopenharmony_ci .proc_open = pktgen_if_open, 17128c2ecf20Sopenharmony_ci .proc_read = seq_read, 17138c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 17148c2ecf20Sopenharmony_ci .proc_write = pktgen_if_write, 17158c2ecf20Sopenharmony_ci .proc_release = single_release, 17168c2ecf20Sopenharmony_ci}; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic int pktgen_thread_show(struct seq_file *seq, void *v) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci struct pktgen_thread *t = seq->private; 17218c2ecf20Sopenharmony_ci const struct pktgen_dev *pkt_dev; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci BUG_ON(!t); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci seq_puts(seq, "Running: "); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci rcu_read_lock(); 17288c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 17298c2ecf20Sopenharmony_ci if (pkt_dev->running) 17308c2ecf20Sopenharmony_ci seq_printf(seq, "%s ", pkt_dev->odevname); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci seq_puts(seq, "\nStopped: "); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 17358c2ecf20Sopenharmony_ci if (!pkt_dev->running) 17368c2ecf20Sopenharmony_ci seq_printf(seq, "%s ", pkt_dev->odevname); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (t->result[0]) 17398c2ecf20Sopenharmony_ci seq_printf(seq, "\nResult: %s\n", t->result); 17408c2ecf20Sopenharmony_ci else 17418c2ecf20Sopenharmony_ci seq_puts(seq, "\nResult: NA\n"); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci rcu_read_unlock(); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci return 0; 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cistatic ssize_t pktgen_thread_write(struct file *file, 17498c2ecf20Sopenharmony_ci const char __user * user_buffer, 17508c2ecf20Sopenharmony_ci size_t count, loff_t * offset) 17518c2ecf20Sopenharmony_ci{ 17528c2ecf20Sopenharmony_ci struct seq_file *seq = file->private_data; 17538c2ecf20Sopenharmony_ci struct pktgen_thread *t = seq->private; 17548c2ecf20Sopenharmony_ci int i, max, len, ret; 17558c2ecf20Sopenharmony_ci char name[40]; 17568c2ecf20Sopenharmony_ci char *pg_result; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci if (count < 1) { 17598c2ecf20Sopenharmony_ci // sprintf(pg_result, "Wrong command format"); 17608c2ecf20Sopenharmony_ci return -EINVAL; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci max = count; 17648c2ecf20Sopenharmony_ci len = count_trail_chars(user_buffer, max); 17658c2ecf20Sopenharmony_ci if (len < 0) 17668c2ecf20Sopenharmony_ci return len; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci i = len; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci /* Read variable name */ 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(name) - 1); 17738c2ecf20Sopenharmony_ci if (len < 0) 17748c2ecf20Sopenharmony_ci return len; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci memset(name, 0, sizeof(name)); 17778c2ecf20Sopenharmony_ci if (copy_from_user(name, &user_buffer[i], len)) 17788c2ecf20Sopenharmony_ci return -EFAULT; 17798c2ecf20Sopenharmony_ci i += len; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci max = count - i; 17828c2ecf20Sopenharmony_ci len = count_trail_chars(&user_buffer[i], max); 17838c2ecf20Sopenharmony_ci if (len < 0) 17848c2ecf20Sopenharmony_ci return len; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci i += len; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (debug) 17898c2ecf20Sopenharmony_ci pr_debug("t=%s, count=%lu\n", name, (unsigned long)count); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (!t) { 17928c2ecf20Sopenharmony_ci pr_err("ERROR: No thread\n"); 17938c2ecf20Sopenharmony_ci ret = -EINVAL; 17948c2ecf20Sopenharmony_ci goto out; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci pg_result = &(t->result[0]); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci if (!strcmp(name, "add_device")) { 18008c2ecf20Sopenharmony_ci char f[32]; 18018c2ecf20Sopenharmony_ci memset(f, 0, 32); 18028c2ecf20Sopenharmony_ci len = strn_len(&user_buffer[i], sizeof(f) - 1); 18038c2ecf20Sopenharmony_ci if (len < 0) { 18048c2ecf20Sopenharmony_ci ret = len; 18058c2ecf20Sopenharmony_ci goto out; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci if (copy_from_user(f, &user_buffer[i], len)) 18088c2ecf20Sopenharmony_ci return -EFAULT; 18098c2ecf20Sopenharmony_ci i += len; 18108c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 18118c2ecf20Sopenharmony_ci ret = pktgen_add_device(t, f); 18128c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 18138c2ecf20Sopenharmony_ci if (!ret) { 18148c2ecf20Sopenharmony_ci ret = count; 18158c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: add_device=%s", f); 18168c2ecf20Sopenharmony_ci } else 18178c2ecf20Sopenharmony_ci sprintf(pg_result, "ERROR: can not add device %s", f); 18188c2ecf20Sopenharmony_ci goto out; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci if (!strcmp(name, "rem_device_all")) { 18228c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 18238c2ecf20Sopenharmony_ci t->control |= T_REMDEVALL; 18248c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 18258c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18268c2ecf20Sopenharmony_ci ret = count; 18278c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: rem_device_all"); 18288c2ecf20Sopenharmony_ci goto out; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci if (!strcmp(name, "max_before_softirq")) { 18328c2ecf20Sopenharmony_ci sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18338c2ecf20Sopenharmony_ci ret = count; 18348c2ecf20Sopenharmony_ci goto out; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci ret = -EINVAL; 18388c2ecf20Sopenharmony_ciout: 18398c2ecf20Sopenharmony_ci return ret; 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_cistatic int pktgen_thread_open(struct inode *inode, struct file *file) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci return single_open(file, pktgen_thread_show, PDE_DATA(inode)); 18458c2ecf20Sopenharmony_ci} 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_cistatic const struct proc_ops pktgen_thread_proc_ops = { 18488c2ecf20Sopenharmony_ci .proc_open = pktgen_thread_open, 18498c2ecf20Sopenharmony_ci .proc_read = seq_read, 18508c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 18518c2ecf20Sopenharmony_ci .proc_write = pktgen_thread_write, 18528c2ecf20Sopenharmony_ci .proc_release = single_release, 18538c2ecf20Sopenharmony_ci}; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci/* Think find or remove for NN */ 18568c2ecf20Sopenharmony_cistatic struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, 18578c2ecf20Sopenharmony_ci const char *ifname, int remove) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci struct pktgen_thread *t; 18608c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev = NULL; 18618c2ecf20Sopenharmony_ci bool exact = (remove == FIND); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) { 18648c2ecf20Sopenharmony_ci pkt_dev = pktgen_find_dev(t, ifname, exact); 18658c2ecf20Sopenharmony_ci if (pkt_dev) { 18668c2ecf20Sopenharmony_ci if (remove) { 18678c2ecf20Sopenharmony_ci pkt_dev->removal_mark = 1; 18688c2ecf20Sopenharmony_ci t->control |= T_REMDEV; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci break; 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci return pkt_dev; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci/* 18778c2ecf20Sopenharmony_ci * mark a device for removal 18788c2ecf20Sopenharmony_ci */ 18798c2ecf20Sopenharmony_cistatic void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev = NULL; 18828c2ecf20Sopenharmony_ci const int max_tries = 10, msec_per_try = 125; 18838c2ecf20Sopenharmony_ci int i = 0; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 18868c2ecf20Sopenharmony_ci pr_debug("%s: marking %s for removal\n", __func__, ifname); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci while (1) { 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE); 18918c2ecf20Sopenharmony_ci if (pkt_dev == NULL) 18928c2ecf20Sopenharmony_ci break; /* success */ 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 18958c2ecf20Sopenharmony_ci pr_debug("%s: waiting for %s to disappear....\n", 18968c2ecf20Sopenharmony_ci __func__, ifname); 18978c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 18988c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci if (++i >= max_tries) { 19018c2ecf20Sopenharmony_ci pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 19028c2ecf20Sopenharmony_ci __func__, msec_per_try * i, ifname); 19038c2ecf20Sopenharmony_ci break; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_cistatic void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci struct pktgen_thread *t; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) { 19188c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci if_lock(t); 19218c2ecf20Sopenharmony_ci list_for_each_entry(pkt_dev, &t->if_list, list) { 19228c2ecf20Sopenharmony_ci if (pkt_dev->odev != dev) 19238c2ecf20Sopenharmony_ci continue; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci proc_remove(pkt_dev->entry); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci pkt_dev->entry = proc_create_data(dev->name, 0600, 19288c2ecf20Sopenharmony_ci pn->proc_dir, 19298c2ecf20Sopenharmony_ci &pktgen_if_proc_ops, 19308c2ecf20Sopenharmony_ci pkt_dev); 19318c2ecf20Sopenharmony_ci if (!pkt_dev->entry) 19328c2ecf20Sopenharmony_ci pr_err("can't move proc entry for '%s'\n", 19338c2ecf20Sopenharmony_ci dev->name); 19348c2ecf20Sopenharmony_ci break; 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci if_unlock(t); 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic int pktgen_device_event(struct notifier_block *unused, 19428c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 19458c2ecf20Sopenharmony_ci struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci if (pn->pktgen_exiting) 19488c2ecf20Sopenharmony_ci return NOTIFY_DONE; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci /* It is OK that we do not hold the group lock right now, 19518c2ecf20Sopenharmony_ci * as we run under the RTNL lock. 19528c2ecf20Sopenharmony_ci */ 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci switch (event) { 19558c2ecf20Sopenharmony_ci case NETDEV_CHANGENAME: 19568c2ecf20Sopenharmony_ci pktgen_change_name(pn, dev); 19578c2ecf20Sopenharmony_ci break; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci case NETDEV_UNREGISTER: 19608c2ecf20Sopenharmony_ci pktgen_mark_device(pn, dev->name); 19618c2ecf20Sopenharmony_ci break; 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci return NOTIFY_DONE; 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistatic struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn, 19688c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev, 19698c2ecf20Sopenharmony_ci const char *ifname) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci char b[IFNAMSIZ+5]; 19728c2ecf20Sopenharmony_ci int i; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci for (i = 0; ifname[i] != '@'; i++) { 19758c2ecf20Sopenharmony_ci if (i == IFNAMSIZ) 19768c2ecf20Sopenharmony_ci break; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci b[i] = ifname[i]; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci b[i] = 0; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci return dev_get_by_name(pn->net, b); 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci/* Associate pktgen_dev with a device. */ 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_cistatic int pktgen_setup_dev(const struct pktgen_net *pn, 19898c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev, const char *ifname) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci struct net_device *odev; 19928c2ecf20Sopenharmony_ci int err; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci /* Clean old setups */ 19958c2ecf20Sopenharmony_ci if (pkt_dev->odev) { 19968c2ecf20Sopenharmony_ci dev_put(pkt_dev->odev); 19978c2ecf20Sopenharmony_ci pkt_dev->odev = NULL; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname); 20018c2ecf20Sopenharmony_ci if (!odev) { 20028c2ecf20Sopenharmony_ci pr_err("no such netdevice: \"%s\"\n", ifname); 20038c2ecf20Sopenharmony_ci return -ENODEV; 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci if (odev->type != ARPHRD_ETHER && odev->type != ARPHRD_LOOPBACK) { 20078c2ecf20Sopenharmony_ci pr_err("not an ethernet or loopback device: \"%s\"\n", ifname); 20088c2ecf20Sopenharmony_ci err = -EINVAL; 20098c2ecf20Sopenharmony_ci } else if (!netif_running(odev)) { 20108c2ecf20Sopenharmony_ci pr_err("device is down: \"%s\"\n", ifname); 20118c2ecf20Sopenharmony_ci err = -ENETDOWN; 20128c2ecf20Sopenharmony_ci } else { 20138c2ecf20Sopenharmony_ci pkt_dev->odev = odev; 20148c2ecf20Sopenharmony_ci return 0; 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci dev_put(odev); 20188c2ecf20Sopenharmony_ci return err; 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci/* Read pkt_dev from the interface and set up internal pktgen_dev 20228c2ecf20Sopenharmony_ci * structure to have the right information to create/send packets 20238c2ecf20Sopenharmony_ci */ 20248c2ecf20Sopenharmony_cistatic void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20258c2ecf20Sopenharmony_ci{ 20268c2ecf20Sopenharmony_ci int ntxq; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci if (!pkt_dev->odev) { 20298c2ecf20Sopenharmony_ci pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 20308c2ecf20Sopenharmony_ci sprintf(pkt_dev->result, 20318c2ecf20Sopenharmony_ci "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20328c2ecf20Sopenharmony_ci return; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* make sure that we don't pick a non-existing transmit queue */ 20368c2ecf20Sopenharmony_ci ntxq = pkt_dev->odev->real_num_tx_queues; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci if (ntxq <= pkt_dev->queue_map_min) { 20398c2ecf20Sopenharmony_ci pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 20408c2ecf20Sopenharmony_ci pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 20418c2ecf20Sopenharmony_ci pkt_dev->odevname); 20428c2ecf20Sopenharmony_ci pkt_dev->queue_map_min = (ntxq ?: 1) - 1; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci if (pkt_dev->queue_map_max >= ntxq) { 20458c2ecf20Sopenharmony_ci pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 20468c2ecf20Sopenharmony_ci pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 20478c2ecf20Sopenharmony_ci pkt_dev->odevname); 20488c2ecf20Sopenharmony_ci pkt_dev->queue_map_max = (ntxq ?: 1) - 1; 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* Default to the interface's mac if not explicitly set. */ 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if (is_zero_ether_addr(pkt_dev->src_mac)) 20548c2ecf20Sopenharmony_ci ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci /* Set up Dest MAC */ 20578c2ecf20Sopenharmony_ci ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPV6) { 20608c2ecf20Sopenharmony_ci int i, set = 0, err = 1; 20618c2ecf20Sopenharmony_ci struct inet6_dev *idev; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (pkt_dev->min_pkt_size == 0) { 20648c2ecf20Sopenharmony_ci pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr) 20658c2ecf20Sopenharmony_ci + sizeof(struct udphdr) 20668c2ecf20Sopenharmony_ci + sizeof(struct pktgen_hdr) 20678c2ecf20Sopenharmony_ci + pkt_dev->pkt_overhead; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(struct in6_addr); i++) 20718c2ecf20Sopenharmony_ci if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20728c2ecf20Sopenharmony_ci set = 1; 20738c2ecf20Sopenharmony_ci break; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci if (!set) { 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci /* 20798c2ecf20Sopenharmony_ci * Use linklevel address if unconfigured. 20808c2ecf20Sopenharmony_ci * 20818c2ecf20Sopenharmony_ci * use ipv6_get_lladdr if/when it's get exported 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci rcu_read_lock(); 20858c2ecf20Sopenharmony_ci idev = __in6_dev_get(pkt_dev->odev); 20868c2ecf20Sopenharmony_ci if (idev) { 20878c2ecf20Sopenharmony_ci struct inet6_ifaddr *ifp; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci read_lock_bh(&idev->lock); 20908c2ecf20Sopenharmony_ci list_for_each_entry(ifp, &idev->addr_list, if_list) { 20918c2ecf20Sopenharmony_ci if ((ifp->scope & IFA_LINK) && 20928c2ecf20Sopenharmony_ci !(ifp->flags & IFA_F_TENTATIVE)) { 20938c2ecf20Sopenharmony_ci pkt_dev->cur_in6_saddr = ifp->addr; 20948c2ecf20Sopenharmony_ci err = 0; 20958c2ecf20Sopenharmony_ci break; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci read_unlock_bh(&idev->lock); 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci rcu_read_unlock(); 21018c2ecf20Sopenharmony_ci if (err) 21028c2ecf20Sopenharmony_ci pr_err("ERROR: IPv6 link address not available\n"); 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci } else { 21058c2ecf20Sopenharmony_ci if (pkt_dev->min_pkt_size == 0) { 21068c2ecf20Sopenharmony_ci pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr) 21078c2ecf20Sopenharmony_ci + sizeof(struct udphdr) 21088c2ecf20Sopenharmony_ci + sizeof(struct pktgen_hdr) 21098c2ecf20Sopenharmony_ci + pkt_dev->pkt_overhead; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci pkt_dev->saddr_min = 0; 21138c2ecf20Sopenharmony_ci pkt_dev->saddr_max = 0; 21148c2ecf20Sopenharmony_ci if (strlen(pkt_dev->src_min) == 0) { 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci struct in_device *in_dev; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci rcu_read_lock(); 21198c2ecf20Sopenharmony_ci in_dev = __in_dev_get_rcu(pkt_dev->odev); 21208c2ecf20Sopenharmony_ci if (in_dev) { 21218c2ecf20Sopenharmony_ci const struct in_ifaddr *ifa; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci ifa = rcu_dereference(in_dev->ifa_list); 21248c2ecf20Sopenharmony_ci if (ifa) { 21258c2ecf20Sopenharmony_ci pkt_dev->saddr_min = ifa->ifa_address; 21268c2ecf20Sopenharmony_ci pkt_dev->saddr_max = pkt_dev->saddr_min; 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci rcu_read_unlock(); 21308c2ecf20Sopenharmony_ci } else { 21318c2ecf20Sopenharmony_ci pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21328c2ecf20Sopenharmony_ci pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21368c2ecf20Sopenharmony_ci pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci /* Initialize current values. */ 21398c2ecf20Sopenharmony_ci pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 21408c2ecf20Sopenharmony_ci if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size) 21418c2ecf20Sopenharmony_ci pkt_dev->max_pkt_size = pkt_dev->min_pkt_size; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci pkt_dev->cur_dst_mac_offset = 0; 21448c2ecf20Sopenharmony_ci pkt_dev->cur_src_mac_offset = 0; 21458c2ecf20Sopenharmony_ci pkt_dev->cur_saddr = pkt_dev->saddr_min; 21468c2ecf20Sopenharmony_ci pkt_dev->cur_daddr = pkt_dev->daddr_min; 21478c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21488c2ecf20Sopenharmony_ci pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21498c2ecf20Sopenharmony_ci pkt_dev->nflows = 0; 21508c2ecf20Sopenharmony_ci} 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_cistatic void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 21548c2ecf20Sopenharmony_ci{ 21558c2ecf20Sopenharmony_ci ktime_t start_time, end_time; 21568c2ecf20Sopenharmony_ci s64 remaining; 21578c2ecf20Sopenharmony_ci struct hrtimer_sleeper t; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci hrtimer_init_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21608c2ecf20Sopenharmony_ci hrtimer_set_expires(&t.timer, spin_until); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 21638c2ecf20Sopenharmony_ci if (remaining <= 0) 21648c2ecf20Sopenharmony_ci goto out; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci start_time = ktime_get(); 21678c2ecf20Sopenharmony_ci if (remaining < 100000) { 21688c2ecf20Sopenharmony_ci /* for small delays (<100us), just loop until limit is reached */ 21698c2ecf20Sopenharmony_ci do { 21708c2ecf20Sopenharmony_ci end_time = ktime_get(); 21718c2ecf20Sopenharmony_ci } while (ktime_compare(end_time, spin_until) < 0); 21728c2ecf20Sopenharmony_ci } else { 21738c2ecf20Sopenharmony_ci do { 21748c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 21758c2ecf20Sopenharmony_ci hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_ABS); 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci if (likely(t.task)) 21788c2ecf20Sopenharmony_ci schedule(); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci hrtimer_cancel(&t.timer); 21818c2ecf20Sopenharmony_ci } while (t.task && pkt_dev->running && !signal_pending(current)); 21828c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 21838c2ecf20Sopenharmony_ci end_time = ktime_get(); 21848c2ecf20Sopenharmony_ci } 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 21878c2ecf20Sopenharmony_ciout: 21888c2ecf20Sopenharmony_ci pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21898c2ecf20Sopenharmony_ci destroy_hrtimer_on_stack(&t.timer); 21908c2ecf20Sopenharmony_ci} 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_cistatic inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 21938c2ecf20Sopenharmony_ci{ 21948c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead = 0; 21958c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 21968c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 21978c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 21988c2ecf20Sopenharmony_ci} 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_cistatic inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 22018c2ecf20Sopenharmony_ci{ 22028c2ecf20Sopenharmony_ci return !!(pkt_dev->flows[flow].flags & F_INIT); 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic inline int f_pick(struct pktgen_dev *pkt_dev) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci int flow = pkt_dev->curfl; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_FLOW_SEQ) { 22108c2ecf20Sopenharmony_ci if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 22118c2ecf20Sopenharmony_ci /* reset time */ 22128c2ecf20Sopenharmony_ci pkt_dev->flows[flow].count = 0; 22138c2ecf20Sopenharmony_ci pkt_dev->flows[flow].flags = 0; 22148c2ecf20Sopenharmony_ci pkt_dev->curfl += 1; 22158c2ecf20Sopenharmony_ci if (pkt_dev->curfl >= pkt_dev->cflows) 22168c2ecf20Sopenharmony_ci pkt_dev->curfl = 0; /*reset */ 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci } else { 22198c2ecf20Sopenharmony_ci flow = prandom_u32() % pkt_dev->cflows; 22208c2ecf20Sopenharmony_ci pkt_dev->curfl = flow; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 22238c2ecf20Sopenharmony_ci pkt_dev->flows[flow].count = 0; 22248c2ecf20Sopenharmony_ci pkt_dev->flows[flow].flags = 0; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci return pkt_dev->curfl; 22298c2ecf20Sopenharmony_ci} 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 22338c2ecf20Sopenharmony_ci/* If there was already an IPSEC SA, we keep it as is, else 22348c2ecf20Sopenharmony_ci * we go look for it ... 22358c2ecf20Sopenharmony_ci*/ 22368c2ecf20Sopenharmony_ci#define DUMMY_MARK 0 22378c2ecf20Sopenharmony_cistatic void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 22388c2ecf20Sopenharmony_ci{ 22398c2ecf20Sopenharmony_ci struct xfrm_state *x = pkt_dev->flows[flow].x; 22408c2ecf20Sopenharmony_ci struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); 22418c2ecf20Sopenharmony_ci if (!x) { 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (pkt_dev->spi) { 22448c2ecf20Sopenharmony_ci /* We need as quick as possible to find the right SA 22458c2ecf20Sopenharmony_ci * Searching with minimum criteria to archieve this. 22468c2ecf20Sopenharmony_ci */ 22478c2ecf20Sopenharmony_ci x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); 22488c2ecf20Sopenharmony_ci } else { 22498c2ecf20Sopenharmony_ci /* slow path: we dont already have xfrm_state */ 22508c2ecf20Sopenharmony_ci x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0, 22518c2ecf20Sopenharmony_ci (xfrm_address_t *)&pkt_dev->cur_daddr, 22528c2ecf20Sopenharmony_ci (xfrm_address_t *)&pkt_dev->cur_saddr, 22538c2ecf20Sopenharmony_ci AF_INET, 22548c2ecf20Sopenharmony_ci pkt_dev->ipsmode, 22558c2ecf20Sopenharmony_ci pkt_dev->ipsproto, 0); 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci if (x) { 22588c2ecf20Sopenharmony_ci pkt_dev->flows[flow].x = x; 22598c2ecf20Sopenharmony_ci set_pkt_overhead(pkt_dev); 22608c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead += x->props.header_len; 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci } 22648c2ecf20Sopenharmony_ci} 22658c2ecf20Sopenharmony_ci#endif 22668c2ecf20Sopenharmony_cistatic void set_cur_queue_map(struct pktgen_dev *pkt_dev) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_QUEUE_MAP_CPU) 22708c2ecf20Sopenharmony_ci pkt_dev->cur_queue_map = smp_processor_id(); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 22738c2ecf20Sopenharmony_ci __u16 t; 22748c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_QUEUE_MAP_RND) { 22758c2ecf20Sopenharmony_ci t = prandom_u32() % 22768c2ecf20Sopenharmony_ci (pkt_dev->queue_map_max - 22778c2ecf20Sopenharmony_ci pkt_dev->queue_map_min + 1) 22788c2ecf20Sopenharmony_ci + pkt_dev->queue_map_min; 22798c2ecf20Sopenharmony_ci } else { 22808c2ecf20Sopenharmony_ci t = pkt_dev->cur_queue_map + 1; 22818c2ecf20Sopenharmony_ci if (t > pkt_dev->queue_map_max) 22828c2ecf20Sopenharmony_ci t = pkt_dev->queue_map_min; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci pkt_dev->cur_queue_map = t; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci/* Increment/randomize headers according to flags and current values 22908c2ecf20Sopenharmony_ci * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 22918c2ecf20Sopenharmony_ci */ 22928c2ecf20Sopenharmony_cistatic void mod_cur_headers(struct pktgen_dev *pkt_dev) 22938c2ecf20Sopenharmony_ci{ 22948c2ecf20Sopenharmony_ci __u32 imn; 22958c2ecf20Sopenharmony_ci __u32 imx; 22968c2ecf20Sopenharmony_ci int flow = 0; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci if (pkt_dev->cflows) 22998c2ecf20Sopenharmony_ci flow = f_pick(pkt_dev); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci /* Deal with source MAC */ 23028c2ecf20Sopenharmony_ci if (pkt_dev->src_mac_count > 1) { 23038c2ecf20Sopenharmony_ci __u32 mc; 23048c2ecf20Sopenharmony_ci __u32 tmp; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_MACSRC_RND) 23078c2ecf20Sopenharmony_ci mc = prandom_u32() % pkt_dev->src_mac_count; 23088c2ecf20Sopenharmony_ci else { 23098c2ecf20Sopenharmony_ci mc = pkt_dev->cur_src_mac_offset++; 23108c2ecf20Sopenharmony_ci if (pkt_dev->cur_src_mac_offset >= 23118c2ecf20Sopenharmony_ci pkt_dev->src_mac_count) 23128c2ecf20Sopenharmony_ci pkt_dev->cur_src_mac_offset = 0; 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23168c2ecf20Sopenharmony_ci pkt_dev->hh[11] = tmp; 23178c2ecf20Sopenharmony_ci tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23188c2ecf20Sopenharmony_ci pkt_dev->hh[10] = tmp; 23198c2ecf20Sopenharmony_ci tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23208c2ecf20Sopenharmony_ci pkt_dev->hh[9] = tmp; 23218c2ecf20Sopenharmony_ci tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23228c2ecf20Sopenharmony_ci pkt_dev->hh[8] = tmp; 23238c2ecf20Sopenharmony_ci tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23248c2ecf20Sopenharmony_ci pkt_dev->hh[7] = tmp; 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci /* Deal with Destination MAC */ 23288c2ecf20Sopenharmony_ci if (pkt_dev->dst_mac_count > 1) { 23298c2ecf20Sopenharmony_ci __u32 mc; 23308c2ecf20Sopenharmony_ci __u32 tmp; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_MACDST_RND) 23338c2ecf20Sopenharmony_ci mc = prandom_u32() % pkt_dev->dst_mac_count; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci else { 23368c2ecf20Sopenharmony_ci mc = pkt_dev->cur_dst_mac_offset++; 23378c2ecf20Sopenharmony_ci if (pkt_dev->cur_dst_mac_offset >= 23388c2ecf20Sopenharmony_ci pkt_dev->dst_mac_count) { 23398c2ecf20Sopenharmony_ci pkt_dev->cur_dst_mac_offset = 0; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23448c2ecf20Sopenharmony_ci pkt_dev->hh[5] = tmp; 23458c2ecf20Sopenharmony_ci tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23468c2ecf20Sopenharmony_ci pkt_dev->hh[4] = tmp; 23478c2ecf20Sopenharmony_ci tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23488c2ecf20Sopenharmony_ci pkt_dev->hh[3] = tmp; 23498c2ecf20Sopenharmony_ci tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23508c2ecf20Sopenharmony_ci pkt_dev->hh[2] = tmp; 23518c2ecf20Sopenharmony_ci tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23528c2ecf20Sopenharmony_ci pkt_dev->hh[1] = tmp; 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_MPLS_RND) { 23568c2ecf20Sopenharmony_ci unsigned int i; 23578c2ecf20Sopenharmony_ci for (i = 0; i < pkt_dev->nr_labels; i++) 23588c2ecf20Sopenharmony_ci if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 23598c2ecf20Sopenharmony_ci pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 23608c2ecf20Sopenharmony_ci ((__force __be32)prandom_u32() & 23618c2ecf20Sopenharmony_ci htonl(0x000fffff)); 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 23658c2ecf20Sopenharmony_ci pkt_dev->vlan_id = prandom_u32() & (4096 - 1); 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 23698c2ecf20Sopenharmony_ci pkt_dev->svlan_id = prandom_u32() & (4096 - 1); 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23738c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_UDPSRC_RND) 23748c2ecf20Sopenharmony_ci pkt_dev->cur_udp_src = prandom_u32() % 23758c2ecf20Sopenharmony_ci (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23768c2ecf20Sopenharmony_ci + pkt_dev->udp_src_min; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci else { 23798c2ecf20Sopenharmony_ci pkt_dev->cur_udp_src++; 23808c2ecf20Sopenharmony_ci if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 23818c2ecf20Sopenharmony_ci pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci } 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 23868c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_UDPDST_RND) { 23878c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst = prandom_u32() % 23888c2ecf20Sopenharmony_ci (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 23898c2ecf20Sopenharmony_ci + pkt_dev->udp_dst_min; 23908c2ecf20Sopenharmony_ci } else { 23918c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst++; 23928c2ecf20Sopenharmony_ci if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 23938c2ecf20Sopenharmony_ci pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (!(pkt_dev->flags & F_IPV6)) { 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci imn = ntohl(pkt_dev->saddr_min); 24008c2ecf20Sopenharmony_ci imx = ntohl(pkt_dev->saddr_max); 24018c2ecf20Sopenharmony_ci if (imn < imx) { 24028c2ecf20Sopenharmony_ci __u32 t; 24038c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPSRC_RND) 24048c2ecf20Sopenharmony_ci t = prandom_u32() % (imx - imn) + imn; 24058c2ecf20Sopenharmony_ci else { 24068c2ecf20Sopenharmony_ci t = ntohl(pkt_dev->cur_saddr); 24078c2ecf20Sopenharmony_ci t++; 24088c2ecf20Sopenharmony_ci if (t > imx) 24098c2ecf20Sopenharmony_ci t = imn; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci pkt_dev->cur_saddr = htonl(t); 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24168c2ecf20Sopenharmony_ci pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24178c2ecf20Sopenharmony_ci } else { 24188c2ecf20Sopenharmony_ci imn = ntohl(pkt_dev->daddr_min); 24198c2ecf20Sopenharmony_ci imx = ntohl(pkt_dev->daddr_max); 24208c2ecf20Sopenharmony_ci if (imn < imx) { 24218c2ecf20Sopenharmony_ci __u32 t; 24228c2ecf20Sopenharmony_ci __be32 s; 24238c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPDST_RND) { 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci do { 24268c2ecf20Sopenharmony_ci t = prandom_u32() % 24278c2ecf20Sopenharmony_ci (imx - imn) + imn; 24288c2ecf20Sopenharmony_ci s = htonl(t); 24298c2ecf20Sopenharmony_ci } while (ipv4_is_loopback(s) || 24308c2ecf20Sopenharmony_ci ipv4_is_multicast(s) || 24318c2ecf20Sopenharmony_ci ipv4_is_lbcast(s) || 24328c2ecf20Sopenharmony_ci ipv4_is_zeronet(s) || 24338c2ecf20Sopenharmony_ci ipv4_is_local_multicast(s)); 24348c2ecf20Sopenharmony_ci pkt_dev->cur_daddr = s; 24358c2ecf20Sopenharmony_ci } else { 24368c2ecf20Sopenharmony_ci t = ntohl(pkt_dev->cur_daddr); 24378c2ecf20Sopenharmony_ci t++; 24388c2ecf20Sopenharmony_ci if (t > imx) { 24398c2ecf20Sopenharmony_ci t = imn; 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci pkt_dev->cur_daddr = htonl(t); 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci if (pkt_dev->cflows) { 24458c2ecf20Sopenharmony_ci pkt_dev->flows[flow].flags |= F_INIT; 24468c2ecf20Sopenharmony_ci pkt_dev->flows[flow].cur_daddr = 24478c2ecf20Sopenharmony_ci pkt_dev->cur_daddr; 24488c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 24498c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPSEC) 24508c2ecf20Sopenharmony_ci get_ipsec_sa(pkt_dev, flow); 24518c2ecf20Sopenharmony_ci#endif 24528c2ecf20Sopenharmony_ci pkt_dev->nflows++; 24538c2ecf20Sopenharmony_ci } 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci } else { /* IPV6 * */ 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) { 24588c2ecf20Sopenharmony_ci int i; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci /* Only random destinations yet */ 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 24638c2ecf20Sopenharmony_ci pkt_dev->cur_in6_daddr.s6_addr32[i] = 24648c2ecf20Sopenharmony_ci (((__force __be32)prandom_u32() | 24658c2ecf20Sopenharmony_ci pkt_dev->min_in6_daddr.s6_addr32[i]) & 24668c2ecf20Sopenharmony_ci pkt_dev->max_in6_daddr.s6_addr32[i]); 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24728c2ecf20Sopenharmony_ci __u32 t; 24738c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_TXSIZE_RND) { 24748c2ecf20Sopenharmony_ci t = prandom_u32() % 24758c2ecf20Sopenharmony_ci (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24768c2ecf20Sopenharmony_ci + pkt_dev->min_pkt_size; 24778c2ecf20Sopenharmony_ci } else { 24788c2ecf20Sopenharmony_ci t = pkt_dev->cur_pkt_size + 1; 24798c2ecf20Sopenharmony_ci if (t > pkt_dev->max_pkt_size) 24808c2ecf20Sopenharmony_ci t = pkt_dev->min_pkt_size; 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci pkt_dev->cur_pkt_size = t; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci set_cur_queue_map(pkt_dev); 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci pkt_dev->flows[flow].count++; 24888c2ecf20Sopenharmony_ci} 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 24928c2ecf20Sopenharmony_cistatic u32 pktgen_dst_metrics[RTAX_MAX + 1] = { 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ 24958c2ecf20Sopenharmony_ci}; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_cistatic int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 24988c2ecf20Sopenharmony_ci{ 24998c2ecf20Sopenharmony_ci struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 25008c2ecf20Sopenharmony_ci int err = 0; 25018c2ecf20Sopenharmony_ci struct net *net = dev_net(pkt_dev->odev); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci if (!x) 25048c2ecf20Sopenharmony_ci return 0; 25058c2ecf20Sopenharmony_ci /* XXX: we dont support tunnel mode for now until 25068c2ecf20Sopenharmony_ci * we resolve the dst issue */ 25078c2ecf20Sopenharmony_ci if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) 25088c2ecf20Sopenharmony_ci return 0; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci /* But when user specify an valid SPI, transformation 25118c2ecf20Sopenharmony_ci * supports both transport/tunnel mode + ESP/AH type. 25128c2ecf20Sopenharmony_ci */ 25138c2ecf20Sopenharmony_ci if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) 25148c2ecf20Sopenharmony_ci skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 25178c2ecf20Sopenharmony_ci err = pktgen_xfrm_outer_mode_output(x, skb); 25188c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 25198c2ecf20Sopenharmony_ci if (err) { 25208c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); 25218c2ecf20Sopenharmony_ci goto error; 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci err = x->type->output(x, skb); 25248c2ecf20Sopenharmony_ci if (err) { 25258c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); 25268c2ecf20Sopenharmony_ci goto error; 25278c2ecf20Sopenharmony_ci } 25288c2ecf20Sopenharmony_ci spin_lock_bh(&x->lock); 25298c2ecf20Sopenharmony_ci x->curlft.bytes += skb->len; 25308c2ecf20Sopenharmony_ci x->curlft.packets++; 25318c2ecf20Sopenharmony_ci spin_unlock_bh(&x->lock); 25328c2ecf20Sopenharmony_cierror: 25338c2ecf20Sopenharmony_ci return err; 25348c2ecf20Sopenharmony_ci} 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_cistatic void free_SAs(struct pktgen_dev *pkt_dev) 25378c2ecf20Sopenharmony_ci{ 25388c2ecf20Sopenharmony_ci if (pkt_dev->cflows) { 25398c2ecf20Sopenharmony_ci /* let go of the SAs if we have them */ 25408c2ecf20Sopenharmony_ci int i; 25418c2ecf20Sopenharmony_ci for (i = 0; i < pkt_dev->cflows; i++) { 25428c2ecf20Sopenharmony_ci struct xfrm_state *x = pkt_dev->flows[i].x; 25438c2ecf20Sopenharmony_ci if (x) { 25448c2ecf20Sopenharmony_ci xfrm_state_put(x); 25458c2ecf20Sopenharmony_ci pkt_dev->flows[i].x = NULL; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci } 25498c2ecf20Sopenharmony_ci} 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_cistatic int process_ipsec(struct pktgen_dev *pkt_dev, 25528c2ecf20Sopenharmony_ci struct sk_buff *skb, __be16 protocol) 25538c2ecf20Sopenharmony_ci{ 25548c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPSEC) { 25558c2ecf20Sopenharmony_ci struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 25568c2ecf20Sopenharmony_ci int nhead = 0; 25578c2ecf20Sopenharmony_ci if (x) { 25588c2ecf20Sopenharmony_ci struct ethhdr *eth; 25598c2ecf20Sopenharmony_ci struct iphdr *iph; 25608c2ecf20Sopenharmony_ci int ret; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci nhead = x->props.header_len - skb_headroom(skb); 25638c2ecf20Sopenharmony_ci if (nhead > 0) { 25648c2ecf20Sopenharmony_ci ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 25658c2ecf20Sopenharmony_ci if (ret < 0) { 25668c2ecf20Sopenharmony_ci pr_err("Error expanding ipsec packet %d\n", 25678c2ecf20Sopenharmony_ci ret); 25688c2ecf20Sopenharmony_ci goto err; 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci /* ipsec is not expecting ll header */ 25738c2ecf20Sopenharmony_ci skb_pull(skb, ETH_HLEN); 25748c2ecf20Sopenharmony_ci ret = pktgen_output_ipsec(skb, pkt_dev); 25758c2ecf20Sopenharmony_ci if (ret) { 25768c2ecf20Sopenharmony_ci pr_err("Error creating ipsec packet %d\n", ret); 25778c2ecf20Sopenharmony_ci goto err; 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci /* restore ll */ 25808c2ecf20Sopenharmony_ci eth = skb_push(skb, ETH_HLEN); 25818c2ecf20Sopenharmony_ci memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN); 25828c2ecf20Sopenharmony_ci eth->h_proto = protocol; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci /* Update IPv4 header len as well as checksum value */ 25858c2ecf20Sopenharmony_ci iph = ip_hdr(skb); 25868c2ecf20Sopenharmony_ci iph->tot_len = htons(skb->len - ETH_HLEN); 25878c2ecf20Sopenharmony_ci ip_send_check(iph); 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci return 1; 25918c2ecf20Sopenharmony_cierr: 25928c2ecf20Sopenharmony_ci kfree_skb(skb); 25938c2ecf20Sopenharmony_ci return 0; 25948c2ecf20Sopenharmony_ci} 25958c2ecf20Sopenharmony_ci#endif 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_cistatic void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 25988c2ecf20Sopenharmony_ci{ 25998c2ecf20Sopenharmony_ci unsigned int i; 26008c2ecf20Sopenharmony_ci for (i = 0; i < pkt_dev->nr_labels; i++) 26018c2ecf20Sopenharmony_ci *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci mpls--; 26048c2ecf20Sopenharmony_ci *mpls |= MPLS_STACK_BOTTOM; 26058c2ecf20Sopenharmony_ci} 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_cistatic inline __be16 build_tci(unsigned int id, unsigned int cfi, 26088c2ecf20Sopenharmony_ci unsigned int prio) 26098c2ecf20Sopenharmony_ci{ 26108c2ecf20Sopenharmony_ci return htons(id | (cfi << 12) | (prio << 13)); 26118c2ecf20Sopenharmony_ci} 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_cistatic void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, 26148c2ecf20Sopenharmony_ci int datalen) 26158c2ecf20Sopenharmony_ci{ 26168c2ecf20Sopenharmony_ci struct timespec64 timestamp; 26178c2ecf20Sopenharmony_ci struct pktgen_hdr *pgh; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci pgh = skb_put(skb, sizeof(*pgh)); 26208c2ecf20Sopenharmony_ci datalen -= sizeof(*pgh); 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci if (pkt_dev->nfrags <= 0) { 26238c2ecf20Sopenharmony_ci skb_put_zero(skb, datalen); 26248c2ecf20Sopenharmony_ci } else { 26258c2ecf20Sopenharmony_ci int frags = pkt_dev->nfrags; 26268c2ecf20Sopenharmony_ci int i, len; 26278c2ecf20Sopenharmony_ci int frag_len; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci if (frags > MAX_SKB_FRAGS) 26318c2ecf20Sopenharmony_ci frags = MAX_SKB_FRAGS; 26328c2ecf20Sopenharmony_ci len = datalen - frags * PAGE_SIZE; 26338c2ecf20Sopenharmony_ci if (len > 0) { 26348c2ecf20Sopenharmony_ci skb_put_zero(skb, len); 26358c2ecf20Sopenharmony_ci datalen = frags * PAGE_SIZE; 26368c2ecf20Sopenharmony_ci } 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci i = 0; 26398c2ecf20Sopenharmony_ci frag_len = (datalen/frags) < PAGE_SIZE ? 26408c2ecf20Sopenharmony_ci (datalen/frags) : PAGE_SIZE; 26418c2ecf20Sopenharmony_ci while (datalen > 0) { 26428c2ecf20Sopenharmony_ci if (unlikely(!pkt_dev->page)) { 26438c2ecf20Sopenharmony_ci int node = numa_node_id(); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE)) 26468c2ecf20Sopenharmony_ci node = pkt_dev->node; 26478c2ecf20Sopenharmony_ci pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); 26488c2ecf20Sopenharmony_ci if (!pkt_dev->page) 26498c2ecf20Sopenharmony_ci break; 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci get_page(pkt_dev->page); 26528c2ecf20Sopenharmony_ci skb_frag_set_page(skb, i, pkt_dev->page); 26538c2ecf20Sopenharmony_ci skb_frag_off_set(&skb_shinfo(skb)->frags[i], 0); 26548c2ecf20Sopenharmony_ci /*last fragment, fill rest of data*/ 26558c2ecf20Sopenharmony_ci if (i == (frags - 1)) 26568c2ecf20Sopenharmony_ci skb_frag_size_set(&skb_shinfo(skb)->frags[i], 26578c2ecf20Sopenharmony_ci (datalen < PAGE_SIZE ? datalen : PAGE_SIZE)); 26588c2ecf20Sopenharmony_ci else 26598c2ecf20Sopenharmony_ci skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len); 26608c2ecf20Sopenharmony_ci datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]); 26618c2ecf20Sopenharmony_ci skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 26628c2ecf20Sopenharmony_ci skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); 26638c2ecf20Sopenharmony_ci i++; 26648c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = i; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci /* Stamp the time, and sequence number, 26698c2ecf20Sopenharmony_ci * convert them to network byte order 26708c2ecf20Sopenharmony_ci */ 26718c2ecf20Sopenharmony_ci pgh->pgh_magic = htonl(PKTGEN_MAGIC); 26728c2ecf20Sopenharmony_ci pgh->seq_num = htonl(pkt_dev->seq_num); 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_NO_TIMESTAMP) { 26758c2ecf20Sopenharmony_ci pgh->tv_sec = 0; 26768c2ecf20Sopenharmony_ci pgh->tv_usec = 0; 26778c2ecf20Sopenharmony_ci } else { 26788c2ecf20Sopenharmony_ci /* 26798c2ecf20Sopenharmony_ci * pgh->tv_sec wraps in y2106 when interpreted as unsigned 26808c2ecf20Sopenharmony_ci * as done by wireshark, or y2038 when interpreted as signed. 26818c2ecf20Sopenharmony_ci * This is probably harmless, but if anyone wants to improve 26828c2ecf20Sopenharmony_ci * it, we could introduce a variant that puts 64-bit nanoseconds 26838c2ecf20Sopenharmony_ci * into the respective header bytes. 26848c2ecf20Sopenharmony_ci * This would also be slightly faster to read. 26858c2ecf20Sopenharmony_ci */ 26868c2ecf20Sopenharmony_ci ktime_get_real_ts64(×tamp); 26878c2ecf20Sopenharmony_ci pgh->tv_sec = htonl(timestamp.tv_sec); 26888c2ecf20Sopenharmony_ci pgh->tv_usec = htonl(timestamp.tv_nsec / NSEC_PER_USEC); 26898c2ecf20Sopenharmony_ci } 26908c2ecf20Sopenharmony_ci} 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_cistatic struct sk_buff *pktgen_alloc_skb(struct net_device *dev, 26938c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 26948c2ecf20Sopenharmony_ci{ 26958c2ecf20Sopenharmony_ci unsigned int extralen = LL_RESERVED_SPACE(dev); 26968c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 26978c2ecf20Sopenharmony_ci unsigned int size; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead; 27008c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_NODE) { 27018c2ecf20Sopenharmony_ci int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id(); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node); 27048c2ecf20Sopenharmony_ci if (likely(skb)) { 27058c2ecf20Sopenharmony_ci skb_reserve(skb, NET_SKB_PAD); 27068c2ecf20Sopenharmony_ci skb->dev = dev; 27078c2ecf20Sopenharmony_ci } 27088c2ecf20Sopenharmony_ci } else { 27098c2ecf20Sopenharmony_ci skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT); 27108c2ecf20Sopenharmony_ci } 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci /* the caller pre-fetches from skb->data and reserves for the mac hdr */ 27138c2ecf20Sopenharmony_ci if (likely(skb)) 27148c2ecf20Sopenharmony_ci skb_reserve(skb, extralen - 16); 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci return skb; 27178c2ecf20Sopenharmony_ci} 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_cistatic struct sk_buff *fill_packet_ipv4(struct net_device *odev, 27208c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 27218c2ecf20Sopenharmony_ci{ 27228c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 27238c2ecf20Sopenharmony_ci __u8 *eth; 27248c2ecf20Sopenharmony_ci struct udphdr *udph; 27258c2ecf20Sopenharmony_ci int datalen, iplen; 27268c2ecf20Sopenharmony_ci struct iphdr *iph; 27278c2ecf20Sopenharmony_ci __be16 protocol = htons(ETH_P_IP); 27288c2ecf20Sopenharmony_ci __be32 *mpls; 27298c2ecf20Sopenharmony_ci __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 27308c2ecf20Sopenharmony_ci __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 27318c2ecf20Sopenharmony_ci __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 27328c2ecf20Sopenharmony_ci __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 27338c2ecf20Sopenharmony_ci u16 queue_map; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci if (pkt_dev->nr_labels) 27368c2ecf20Sopenharmony_ci protocol = htons(ETH_P_MPLS_UC); 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci if (pkt_dev->vlan_id != 0xffff) 27398c2ecf20Sopenharmony_ci protocol = htons(ETH_P_8021Q); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci /* Update any of the values, used when we're incrementing various 27428c2ecf20Sopenharmony_ci * fields. 27438c2ecf20Sopenharmony_ci */ 27448c2ecf20Sopenharmony_ci mod_cur_headers(pkt_dev); 27458c2ecf20Sopenharmony_ci queue_map = pkt_dev->cur_queue_map; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci skb = pktgen_alloc_skb(odev, pkt_dev); 27488c2ecf20Sopenharmony_ci if (!skb) { 27498c2ecf20Sopenharmony_ci sprintf(pkt_dev->result, "No memory"); 27508c2ecf20Sopenharmony_ci return NULL; 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci prefetchw(skb->data); 27548c2ecf20Sopenharmony_ci skb_reserve(skb, 16); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci /* Reserve for ethernet and IP header */ 27578c2ecf20Sopenharmony_ci eth = skb_push(skb, 14); 27588c2ecf20Sopenharmony_ci mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 27598c2ecf20Sopenharmony_ci if (pkt_dev->nr_labels) 27608c2ecf20Sopenharmony_ci mpls_push(mpls, pkt_dev); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci if (pkt_dev->vlan_id != 0xffff) { 27638c2ecf20Sopenharmony_ci if (pkt_dev->svlan_id != 0xffff) { 27648c2ecf20Sopenharmony_ci svlan_tci = skb_put(skb, sizeof(__be16)); 27658c2ecf20Sopenharmony_ci *svlan_tci = build_tci(pkt_dev->svlan_id, 27668c2ecf20Sopenharmony_ci pkt_dev->svlan_cfi, 27678c2ecf20Sopenharmony_ci pkt_dev->svlan_p); 27688c2ecf20Sopenharmony_ci svlan_encapsulated_proto = skb_put(skb, 27698c2ecf20Sopenharmony_ci sizeof(__be16)); 27708c2ecf20Sopenharmony_ci *svlan_encapsulated_proto = htons(ETH_P_8021Q); 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci vlan_tci = skb_put(skb, sizeof(__be16)); 27738c2ecf20Sopenharmony_ci *vlan_tci = build_tci(pkt_dev->vlan_id, 27748c2ecf20Sopenharmony_ci pkt_dev->vlan_cfi, 27758c2ecf20Sopenharmony_ci pkt_dev->vlan_p); 27768c2ecf20Sopenharmony_ci vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 27778c2ecf20Sopenharmony_ci *vlan_encapsulated_proto = htons(ETH_P_IP); 27788c2ecf20Sopenharmony_ci } 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 27818c2ecf20Sopenharmony_ci skb_set_network_header(skb, skb->len); 27828c2ecf20Sopenharmony_ci iph = skb_put(skb, sizeof(struct iphdr)); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci skb_set_transport_header(skb, skb->len); 27858c2ecf20Sopenharmony_ci udph = skb_put(skb, sizeof(struct udphdr)); 27868c2ecf20Sopenharmony_ci skb_set_queue_mapping(skb, queue_map); 27878c2ecf20Sopenharmony_ci skb->priority = pkt_dev->skb_priority; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci memcpy(eth, pkt_dev->hh, 12); 27908c2ecf20Sopenharmony_ci *(__be16 *) & eth[12] = protocol; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci /* Eth + IPh + UDPh + mpls */ 27938c2ecf20Sopenharmony_ci datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 27948c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead; 27958c2ecf20Sopenharmony_ci if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) 27968c2ecf20Sopenharmony_ci datalen = sizeof(struct pktgen_hdr); 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci udph->source = htons(pkt_dev->cur_udp_src); 27998c2ecf20Sopenharmony_ci udph->dest = htons(pkt_dev->cur_udp_dst); 28008c2ecf20Sopenharmony_ci udph->len = htons(datalen + 8); /* DATA + udphdr */ 28018c2ecf20Sopenharmony_ci udph->check = 0; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci iph->ihl = 5; 28048c2ecf20Sopenharmony_ci iph->version = 4; 28058c2ecf20Sopenharmony_ci iph->ttl = 32; 28068c2ecf20Sopenharmony_ci iph->tos = pkt_dev->tos; 28078c2ecf20Sopenharmony_ci iph->protocol = IPPROTO_UDP; /* UDP */ 28088c2ecf20Sopenharmony_ci iph->saddr = pkt_dev->cur_saddr; 28098c2ecf20Sopenharmony_ci iph->daddr = pkt_dev->cur_daddr; 28108c2ecf20Sopenharmony_ci iph->id = htons(pkt_dev->ip_id); 28118c2ecf20Sopenharmony_ci pkt_dev->ip_id++; 28128c2ecf20Sopenharmony_ci iph->frag_off = 0; 28138c2ecf20Sopenharmony_ci iplen = 20 + 8 + datalen; 28148c2ecf20Sopenharmony_ci iph->tot_len = htons(iplen); 28158c2ecf20Sopenharmony_ci ip_send_check(iph); 28168c2ecf20Sopenharmony_ci skb->protocol = protocol; 28178c2ecf20Sopenharmony_ci skb->dev = odev; 28188c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci pktgen_finalize_skb(pkt_dev, skb, datalen); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci if (!(pkt_dev->flags & F_UDPCSUM)) { 28238c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 28248c2ecf20Sopenharmony_ci } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) { 28258c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_PARTIAL; 28268c2ecf20Sopenharmony_ci skb->csum = 0; 28278c2ecf20Sopenharmony_ci udp4_hwcsum(skb, iph->saddr, iph->daddr); 28288c2ecf20Sopenharmony_ci } else { 28298c2ecf20Sopenharmony_ci __wsum csum = skb_checksum(skb, skb_transport_offset(skb), datalen + 8, 0); 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci /* add protocol-dependent pseudo-header */ 28328c2ecf20Sopenharmony_ci udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 28338c2ecf20Sopenharmony_ci datalen + 8, IPPROTO_UDP, csum); 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci if (udph->check == 0) 28368c2ecf20Sopenharmony_ci udph->check = CSUM_MANGLED_0; 28378c2ecf20Sopenharmony_ci } 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 28408c2ecf20Sopenharmony_ci if (!process_ipsec(pkt_dev, skb, protocol)) 28418c2ecf20Sopenharmony_ci return NULL; 28428c2ecf20Sopenharmony_ci#endif 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci return skb; 28458c2ecf20Sopenharmony_ci} 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_cistatic struct sk_buff *fill_packet_ipv6(struct net_device *odev, 28488c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 28498c2ecf20Sopenharmony_ci{ 28508c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 28518c2ecf20Sopenharmony_ci __u8 *eth; 28528c2ecf20Sopenharmony_ci struct udphdr *udph; 28538c2ecf20Sopenharmony_ci int datalen, udplen; 28548c2ecf20Sopenharmony_ci struct ipv6hdr *iph; 28558c2ecf20Sopenharmony_ci __be16 protocol = htons(ETH_P_IPV6); 28568c2ecf20Sopenharmony_ci __be32 *mpls; 28578c2ecf20Sopenharmony_ci __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 28588c2ecf20Sopenharmony_ci __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 28598c2ecf20Sopenharmony_ci __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 28608c2ecf20Sopenharmony_ci __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 28618c2ecf20Sopenharmony_ci u16 queue_map; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci if (pkt_dev->nr_labels) 28648c2ecf20Sopenharmony_ci protocol = htons(ETH_P_MPLS_UC); 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci if (pkt_dev->vlan_id != 0xffff) 28678c2ecf20Sopenharmony_ci protocol = htons(ETH_P_8021Q); 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci /* Update any of the values, used when we're incrementing various 28708c2ecf20Sopenharmony_ci * fields. 28718c2ecf20Sopenharmony_ci */ 28728c2ecf20Sopenharmony_ci mod_cur_headers(pkt_dev); 28738c2ecf20Sopenharmony_ci queue_map = pkt_dev->cur_queue_map; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci skb = pktgen_alloc_skb(odev, pkt_dev); 28768c2ecf20Sopenharmony_ci if (!skb) { 28778c2ecf20Sopenharmony_ci sprintf(pkt_dev->result, "No memory"); 28788c2ecf20Sopenharmony_ci return NULL; 28798c2ecf20Sopenharmony_ci } 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci prefetchw(skb->data); 28828c2ecf20Sopenharmony_ci skb_reserve(skb, 16); 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci /* Reserve for ethernet and IP header */ 28858c2ecf20Sopenharmony_ci eth = skb_push(skb, 14); 28868c2ecf20Sopenharmony_ci mpls = skb_put(skb, pkt_dev->nr_labels * sizeof(__u32)); 28878c2ecf20Sopenharmony_ci if (pkt_dev->nr_labels) 28888c2ecf20Sopenharmony_ci mpls_push(mpls, pkt_dev); 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci if (pkt_dev->vlan_id != 0xffff) { 28918c2ecf20Sopenharmony_ci if (pkt_dev->svlan_id != 0xffff) { 28928c2ecf20Sopenharmony_ci svlan_tci = skb_put(skb, sizeof(__be16)); 28938c2ecf20Sopenharmony_ci *svlan_tci = build_tci(pkt_dev->svlan_id, 28948c2ecf20Sopenharmony_ci pkt_dev->svlan_cfi, 28958c2ecf20Sopenharmony_ci pkt_dev->svlan_p); 28968c2ecf20Sopenharmony_ci svlan_encapsulated_proto = skb_put(skb, 28978c2ecf20Sopenharmony_ci sizeof(__be16)); 28988c2ecf20Sopenharmony_ci *svlan_encapsulated_proto = htons(ETH_P_8021Q); 28998c2ecf20Sopenharmony_ci } 29008c2ecf20Sopenharmony_ci vlan_tci = skb_put(skb, sizeof(__be16)); 29018c2ecf20Sopenharmony_ci *vlan_tci = build_tci(pkt_dev->vlan_id, 29028c2ecf20Sopenharmony_ci pkt_dev->vlan_cfi, 29038c2ecf20Sopenharmony_ci pkt_dev->vlan_p); 29048c2ecf20Sopenharmony_ci vlan_encapsulated_proto = skb_put(skb, sizeof(__be16)); 29058c2ecf20Sopenharmony_ci *vlan_encapsulated_proto = htons(ETH_P_IPV6); 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 29098c2ecf20Sopenharmony_ci skb_set_network_header(skb, skb->len); 29108c2ecf20Sopenharmony_ci iph = skb_put(skb, sizeof(struct ipv6hdr)); 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci skb_set_transport_header(skb, skb->len); 29138c2ecf20Sopenharmony_ci udph = skb_put(skb, sizeof(struct udphdr)); 29148c2ecf20Sopenharmony_ci skb_set_queue_mapping(skb, queue_map); 29158c2ecf20Sopenharmony_ci skb->priority = pkt_dev->skb_priority; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci memcpy(eth, pkt_dev->hh, 12); 29188c2ecf20Sopenharmony_ci *(__be16 *) ð[12] = protocol; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci /* Eth + IPh + UDPh + mpls */ 29218c2ecf20Sopenharmony_ci datalen = pkt_dev->cur_pkt_size - 14 - 29228c2ecf20Sopenharmony_ci sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 29238c2ecf20Sopenharmony_ci pkt_dev->pkt_overhead; 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { 29268c2ecf20Sopenharmony_ci datalen = sizeof(struct pktgen_hdr); 29278c2ecf20Sopenharmony_ci net_info_ratelimited("increased datalen to %d\n", datalen); 29288c2ecf20Sopenharmony_ci } 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci udplen = datalen + sizeof(struct udphdr); 29318c2ecf20Sopenharmony_ci udph->source = htons(pkt_dev->cur_udp_src); 29328c2ecf20Sopenharmony_ci udph->dest = htons(pkt_dev->cur_udp_dst); 29338c2ecf20Sopenharmony_ci udph->len = htons(udplen); 29348c2ecf20Sopenharmony_ci udph->check = 0; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci if (pkt_dev->traffic_class) { 29398c2ecf20Sopenharmony_ci /* Version + traffic class + flow (0) */ 29408c2ecf20Sopenharmony_ci *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci iph->hop_limit = 32; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci iph->payload_len = htons(udplen); 29468c2ecf20Sopenharmony_ci iph->nexthdr = IPPROTO_UDP; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci iph->daddr = pkt_dev->cur_in6_daddr; 29498c2ecf20Sopenharmony_ci iph->saddr = pkt_dev->cur_in6_saddr; 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci skb->protocol = protocol; 29528c2ecf20Sopenharmony_ci skb->dev = odev; 29538c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci pktgen_finalize_skb(pkt_dev, skb, datalen); 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci if (!(pkt_dev->flags & F_UDPCSUM)) { 29588c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 29598c2ecf20Sopenharmony_ci } else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) { 29608c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_PARTIAL; 29618c2ecf20Sopenharmony_ci skb->csum_start = skb_transport_header(skb) - skb->head; 29628c2ecf20Sopenharmony_ci skb->csum_offset = offsetof(struct udphdr, check); 29638c2ecf20Sopenharmony_ci udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0); 29648c2ecf20Sopenharmony_ci } else { 29658c2ecf20Sopenharmony_ci __wsum csum = skb_checksum(skb, skb_transport_offset(skb), udplen, 0); 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci /* add protocol-dependent pseudo-header */ 29688c2ecf20Sopenharmony_ci udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci if (udph->check == 0) 29718c2ecf20Sopenharmony_ci udph->check = CSUM_MANGLED_0; 29728c2ecf20Sopenharmony_ci } 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci return skb; 29758c2ecf20Sopenharmony_ci} 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_cistatic struct sk_buff *fill_packet(struct net_device *odev, 29788c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 29798c2ecf20Sopenharmony_ci{ 29808c2ecf20Sopenharmony_ci if (pkt_dev->flags & F_IPV6) 29818c2ecf20Sopenharmony_ci return fill_packet_ipv6(odev, pkt_dev); 29828c2ecf20Sopenharmony_ci else 29838c2ecf20Sopenharmony_ci return fill_packet_ipv4(odev, pkt_dev); 29848c2ecf20Sopenharmony_ci} 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_cistatic void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 29878c2ecf20Sopenharmony_ci{ 29888c2ecf20Sopenharmony_ci pkt_dev->seq_num = 1; 29898c2ecf20Sopenharmony_ci pkt_dev->idle_acc = 0; 29908c2ecf20Sopenharmony_ci pkt_dev->sofar = 0; 29918c2ecf20Sopenharmony_ci pkt_dev->tx_bytes = 0; 29928c2ecf20Sopenharmony_ci pkt_dev->errors = 0; 29938c2ecf20Sopenharmony_ci} 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci/* Set up structure for sending pkts, clear counters */ 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_cistatic void pktgen_run(struct pktgen_thread *t) 29988c2ecf20Sopenharmony_ci{ 29998c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev; 30008c2ecf20Sopenharmony_ci int started = 0; 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci func_enter(); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci rcu_read_lock(); 30058c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci /* 30088c2ecf20Sopenharmony_ci * setup odev and create initial packet. 30098c2ecf20Sopenharmony_ci */ 30108c2ecf20Sopenharmony_ci pktgen_setup_inject(pkt_dev); 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci if (pkt_dev->odev) { 30138c2ecf20Sopenharmony_ci pktgen_clear_counters(pkt_dev); 30148c2ecf20Sopenharmony_ci pkt_dev->skb = NULL; 30158c2ecf20Sopenharmony_ci pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci set_pkt_overhead(pkt_dev); 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci strcpy(pkt_dev->result, "Starting"); 30208c2ecf20Sopenharmony_ci pkt_dev->running = 1; /* Cranke yeself! */ 30218c2ecf20Sopenharmony_ci started++; 30228c2ecf20Sopenharmony_ci } else 30238c2ecf20Sopenharmony_ci strcpy(pkt_dev->result, "Error starting"); 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci rcu_read_unlock(); 30268c2ecf20Sopenharmony_ci if (started) 30278c2ecf20Sopenharmony_ci t->control &= ~(T_STOP); 30288c2ecf20Sopenharmony_ci} 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_cistatic void pktgen_stop_all_threads_ifs(struct pktgen_net *pn) 30318c2ecf20Sopenharmony_ci{ 30328c2ecf20Sopenharmony_ci struct pktgen_thread *t; 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci func_enter(); 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) 30398c2ecf20Sopenharmony_ci t->control |= T_STOP; 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 30428c2ecf20Sopenharmony_ci} 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_cistatic int thread_is_running(const struct pktgen_thread *t) 30458c2ecf20Sopenharmony_ci{ 30468c2ecf20Sopenharmony_ci const struct pktgen_dev *pkt_dev; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci rcu_read_lock(); 30498c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pkt_dev, &t->if_list, list) 30508c2ecf20Sopenharmony_ci if (pkt_dev->running) { 30518c2ecf20Sopenharmony_ci rcu_read_unlock(); 30528c2ecf20Sopenharmony_ci return 1; 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci rcu_read_unlock(); 30558c2ecf20Sopenharmony_ci return 0; 30568c2ecf20Sopenharmony_ci} 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_cistatic int pktgen_wait_thread_run(struct pktgen_thread *t) 30598c2ecf20Sopenharmony_ci{ 30608c2ecf20Sopenharmony_ci while (thread_is_running(t)) { 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci /* note: 't' will still be around even after the unlock/lock 30638c2ecf20Sopenharmony_ci * cycle because pktgen_thread threads are only cleared at 30648c2ecf20Sopenharmony_ci * net exit 30658c2ecf20Sopenharmony_ci */ 30668c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 30678c2ecf20Sopenharmony_ci msleep_interruptible(100); 30688c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci if (signal_pending(current)) 30718c2ecf20Sopenharmony_ci goto signal; 30728c2ecf20Sopenharmony_ci } 30738c2ecf20Sopenharmony_ci return 1; 30748c2ecf20Sopenharmony_cisignal: 30758c2ecf20Sopenharmony_ci return 0; 30768c2ecf20Sopenharmony_ci} 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_cistatic int pktgen_wait_all_threads_run(struct pktgen_net *pn) 30798c2ecf20Sopenharmony_ci{ 30808c2ecf20Sopenharmony_ci struct pktgen_thread *t; 30818c2ecf20Sopenharmony_ci int sig = 1; 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci /* prevent from racing with rmmod */ 30848c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 30858c2ecf20Sopenharmony_ci return sig; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) { 30908c2ecf20Sopenharmony_ci sig = pktgen_wait_thread_run(t); 30918c2ecf20Sopenharmony_ci if (sig == 0) 30928c2ecf20Sopenharmony_ci break; 30938c2ecf20Sopenharmony_ci } 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci if (sig == 0) 30968c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) 30978c2ecf20Sopenharmony_ci t->control |= (T_STOP); 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 31008c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 31018c2ecf20Sopenharmony_ci return sig; 31028c2ecf20Sopenharmony_ci} 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_cistatic void pktgen_run_all_threads(struct pktgen_net *pn) 31058c2ecf20Sopenharmony_ci{ 31068c2ecf20Sopenharmony_ci struct pktgen_thread *t; 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci func_enter(); 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) 31138c2ecf20Sopenharmony_ci t->control |= (T_RUN); 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci /* Propagate thread->control */ 31188c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(125)); 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci pktgen_wait_all_threads_run(pn); 31218c2ecf20Sopenharmony_ci} 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_cistatic void pktgen_reset_all_threads(struct pktgen_net *pn) 31248c2ecf20Sopenharmony_ci{ 31258c2ecf20Sopenharmony_ci struct pktgen_thread *t; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci func_enter(); 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci list_for_each_entry(t, &pn->pktgen_threads, th_list) 31328c2ecf20Sopenharmony_ci t->control |= (T_REMDEVALL); 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci /* Propagate thread->control */ 31378c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(125)); 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci pktgen_wait_all_threads_run(pn); 31408c2ecf20Sopenharmony_ci} 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_cistatic void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 31438c2ecf20Sopenharmony_ci{ 31448c2ecf20Sopenharmony_ci __u64 bps, mbps, pps; 31458c2ecf20Sopenharmony_ci char *p = pkt_dev->result; 31468c2ecf20Sopenharmony_ci ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 31478c2ecf20Sopenharmony_ci pkt_dev->started_at); 31488c2ecf20Sopenharmony_ci ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", 31518c2ecf20Sopenharmony_ci (unsigned long long)ktime_to_us(elapsed), 31528c2ecf20Sopenharmony_ci (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 31538c2ecf20Sopenharmony_ci (unsigned long long)ktime_to_us(idle), 31548c2ecf20Sopenharmony_ci (unsigned long long)pkt_dev->sofar, 31558c2ecf20Sopenharmony_ci pkt_dev->cur_pkt_size, nr_frags); 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 31588c2ecf20Sopenharmony_ci ktime_to_ns(elapsed)); 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci bps = pps * 8 * pkt_dev->cur_pkt_size; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci mbps = bps; 31638c2ecf20Sopenharmony_ci do_div(mbps, 1000000); 31648c2ecf20Sopenharmony_ci p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 31658c2ecf20Sopenharmony_ci (unsigned long long)pps, 31668c2ecf20Sopenharmony_ci (unsigned long long)mbps, 31678c2ecf20Sopenharmony_ci (unsigned long long)bps, 31688c2ecf20Sopenharmony_ci (unsigned long long)pkt_dev->errors); 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci/* Set stopped-at timer, remove from running list, do counters & statistics */ 31728c2ecf20Sopenharmony_cistatic int pktgen_stop_device(struct pktgen_dev *pkt_dev) 31738c2ecf20Sopenharmony_ci{ 31748c2ecf20Sopenharmony_ci int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if (!pkt_dev->running) { 31778c2ecf20Sopenharmony_ci pr_warn("interface: %s is already stopped\n", 31788c2ecf20Sopenharmony_ci pkt_dev->odevname); 31798c2ecf20Sopenharmony_ci return -EINVAL; 31808c2ecf20Sopenharmony_ci } 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ci pkt_dev->running = 0; 31838c2ecf20Sopenharmony_ci kfree_skb(pkt_dev->skb); 31848c2ecf20Sopenharmony_ci pkt_dev->skb = NULL; 31858c2ecf20Sopenharmony_ci pkt_dev->stopped_at = ktime_get(); 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci show_results(pkt_dev, nr_frags); 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci return 0; 31908c2ecf20Sopenharmony_ci} 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_cistatic struct pktgen_dev *next_to_run(struct pktgen_thread *t) 31938c2ecf20Sopenharmony_ci{ 31948c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev, *best = NULL; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci rcu_read_lock(); 31978c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 31988c2ecf20Sopenharmony_ci if (!pkt_dev->running) 31998c2ecf20Sopenharmony_ci continue; 32008c2ecf20Sopenharmony_ci if (best == NULL) 32018c2ecf20Sopenharmony_ci best = pkt_dev; 32028c2ecf20Sopenharmony_ci else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) 32038c2ecf20Sopenharmony_ci best = pkt_dev; 32048c2ecf20Sopenharmony_ci } 32058c2ecf20Sopenharmony_ci rcu_read_unlock(); 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci return best; 32088c2ecf20Sopenharmony_ci} 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_cistatic void pktgen_stop(struct pktgen_thread *t) 32118c2ecf20Sopenharmony_ci{ 32128c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev; 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci func_enter(); 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci rcu_read_lock(); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { 32198c2ecf20Sopenharmony_ci pktgen_stop_device(pkt_dev); 32208c2ecf20Sopenharmony_ci } 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci rcu_read_unlock(); 32238c2ecf20Sopenharmony_ci} 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci/* 32268c2ecf20Sopenharmony_ci * one of our devices needs to be removed - find it 32278c2ecf20Sopenharmony_ci * and remove it 32288c2ecf20Sopenharmony_ci */ 32298c2ecf20Sopenharmony_cistatic void pktgen_rem_one_if(struct pktgen_thread *t) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci struct list_head *q, *n; 32328c2ecf20Sopenharmony_ci struct pktgen_dev *cur; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci func_enter(); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci list_for_each_safe(q, n, &t->if_list) { 32378c2ecf20Sopenharmony_ci cur = list_entry(q, struct pktgen_dev, list); 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci if (!cur->removal_mark) 32408c2ecf20Sopenharmony_ci continue; 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci kfree_skb(cur->skb); 32438c2ecf20Sopenharmony_ci cur->skb = NULL; 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci pktgen_remove_device(t, cur); 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci break; 32488c2ecf20Sopenharmony_ci } 32498c2ecf20Sopenharmony_ci} 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_cistatic void pktgen_rem_all_ifs(struct pktgen_thread *t) 32528c2ecf20Sopenharmony_ci{ 32538c2ecf20Sopenharmony_ci struct list_head *q, *n; 32548c2ecf20Sopenharmony_ci struct pktgen_dev *cur; 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci func_enter(); 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci /* Remove all devices, free mem */ 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci list_for_each_safe(q, n, &t->if_list) { 32618c2ecf20Sopenharmony_ci cur = list_entry(q, struct pktgen_dev, list); 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci kfree_skb(cur->skb); 32648c2ecf20Sopenharmony_ci cur->skb = NULL; 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci pktgen_remove_device(t, cur); 32678c2ecf20Sopenharmony_ci } 32688c2ecf20Sopenharmony_ci} 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_cistatic void pktgen_rem_thread(struct pktgen_thread *t) 32718c2ecf20Sopenharmony_ci{ 32728c2ecf20Sopenharmony_ci /* Remove from the thread list */ 32738c2ecf20Sopenharmony_ci remove_proc_entry(t->tsk->comm, t->net->proc_dir); 32748c2ecf20Sopenharmony_ci} 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_cistatic void pktgen_resched(struct pktgen_dev *pkt_dev) 32778c2ecf20Sopenharmony_ci{ 32788c2ecf20Sopenharmony_ci ktime_t idle_start = ktime_get(); 32798c2ecf20Sopenharmony_ci schedule(); 32808c2ecf20Sopenharmony_ci pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 32818c2ecf20Sopenharmony_ci} 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_cistatic void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 32848c2ecf20Sopenharmony_ci{ 32858c2ecf20Sopenharmony_ci ktime_t idle_start = ktime_get(); 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci while (refcount_read(&(pkt_dev->skb->users)) != 1) { 32888c2ecf20Sopenharmony_ci if (signal_pending(current)) 32898c2ecf20Sopenharmony_ci break; 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci if (need_resched()) 32928c2ecf20Sopenharmony_ci pktgen_resched(pkt_dev); 32938c2ecf20Sopenharmony_ci else 32948c2ecf20Sopenharmony_ci cpu_relax(); 32958c2ecf20Sopenharmony_ci } 32968c2ecf20Sopenharmony_ci pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start)); 32978c2ecf20Sopenharmony_ci} 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_cistatic void pktgen_xmit(struct pktgen_dev *pkt_dev) 33008c2ecf20Sopenharmony_ci{ 33018c2ecf20Sopenharmony_ci unsigned int burst = READ_ONCE(pkt_dev->burst); 33028c2ecf20Sopenharmony_ci struct net_device *odev = pkt_dev->odev; 33038c2ecf20Sopenharmony_ci struct netdev_queue *txq; 33048c2ecf20Sopenharmony_ci struct sk_buff *skb; 33058c2ecf20Sopenharmony_ci int ret; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci /* If device is offline, then don't send */ 33088c2ecf20Sopenharmony_ci if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 33098c2ecf20Sopenharmony_ci pktgen_stop_device(pkt_dev); 33108c2ecf20Sopenharmony_ci return; 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci /* This is max DELAY, this has special meaning of 33148c2ecf20Sopenharmony_ci * "never transmit" 33158c2ecf20Sopenharmony_ci */ 33168c2ecf20Sopenharmony_ci if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 33178c2ecf20Sopenharmony_ci pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX); 33188c2ecf20Sopenharmony_ci return; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci /* If no skb or clone count exhausted then get new one */ 33228c2ecf20Sopenharmony_ci if (!pkt_dev->skb || (pkt_dev->last_ok && 33238c2ecf20Sopenharmony_ci ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 33248c2ecf20Sopenharmony_ci /* build a new pkt */ 33258c2ecf20Sopenharmony_ci kfree_skb(pkt_dev->skb); 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci pkt_dev->skb = fill_packet(odev, pkt_dev); 33288c2ecf20Sopenharmony_ci if (pkt_dev->skb == NULL) { 33298c2ecf20Sopenharmony_ci pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 33308c2ecf20Sopenharmony_ci schedule(); 33318c2ecf20Sopenharmony_ci pkt_dev->clone_count--; /* back out increment, OOM */ 33328c2ecf20Sopenharmony_ci return; 33338c2ecf20Sopenharmony_ci } 33348c2ecf20Sopenharmony_ci pkt_dev->last_pkt_size = pkt_dev->skb->len; 33358c2ecf20Sopenharmony_ci pkt_dev->clone_count = 0; /* reset counter */ 33368c2ecf20Sopenharmony_ci } 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci if (pkt_dev->delay && pkt_dev->last_ok) 33398c2ecf20Sopenharmony_ci spin(pkt_dev, pkt_dev->next_tx); 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) { 33428c2ecf20Sopenharmony_ci skb = pkt_dev->skb; 33438c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, skb->dev); 33448c2ecf20Sopenharmony_ci refcount_add(burst, &skb->users); 33458c2ecf20Sopenharmony_ci local_bh_disable(); 33468c2ecf20Sopenharmony_ci do { 33478c2ecf20Sopenharmony_ci ret = netif_receive_skb(skb); 33488c2ecf20Sopenharmony_ci if (ret == NET_RX_DROP) 33498c2ecf20Sopenharmony_ci pkt_dev->errors++; 33508c2ecf20Sopenharmony_ci pkt_dev->sofar++; 33518c2ecf20Sopenharmony_ci pkt_dev->seq_num++; 33528c2ecf20Sopenharmony_ci if (refcount_read(&skb->users) != burst) { 33538c2ecf20Sopenharmony_ci /* skb was queued by rps/rfs or taps, 33548c2ecf20Sopenharmony_ci * so cannot reuse this skb 33558c2ecf20Sopenharmony_ci */ 33568c2ecf20Sopenharmony_ci WARN_ON(refcount_sub_and_test(burst - 1, &skb->users)); 33578c2ecf20Sopenharmony_ci /* get out of the loop and wait 33588c2ecf20Sopenharmony_ci * until skb is consumed 33598c2ecf20Sopenharmony_ci */ 33608c2ecf20Sopenharmony_ci break; 33618c2ecf20Sopenharmony_ci } 33628c2ecf20Sopenharmony_ci /* skb was 'freed' by stack, so clean few 33638c2ecf20Sopenharmony_ci * bits and reuse it 33648c2ecf20Sopenharmony_ci */ 33658c2ecf20Sopenharmony_ci skb_reset_redirect(skb); 33668c2ecf20Sopenharmony_ci } while (--burst > 0); 33678c2ecf20Sopenharmony_ci goto out; /* Skips xmit_mode M_START_XMIT */ 33688c2ecf20Sopenharmony_ci } else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) { 33698c2ecf20Sopenharmony_ci local_bh_disable(); 33708c2ecf20Sopenharmony_ci refcount_inc(&pkt_dev->skb->users); 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_ci ret = dev_queue_xmit(pkt_dev->skb); 33738c2ecf20Sopenharmony_ci switch (ret) { 33748c2ecf20Sopenharmony_ci case NET_XMIT_SUCCESS: 33758c2ecf20Sopenharmony_ci pkt_dev->sofar++; 33768c2ecf20Sopenharmony_ci pkt_dev->seq_num++; 33778c2ecf20Sopenharmony_ci pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 33788c2ecf20Sopenharmony_ci break; 33798c2ecf20Sopenharmony_ci case NET_XMIT_DROP: 33808c2ecf20Sopenharmony_ci case NET_XMIT_CN: 33818c2ecf20Sopenharmony_ci /* These are all valid return codes for a qdisc but 33828c2ecf20Sopenharmony_ci * indicate packets are being dropped or will likely 33838c2ecf20Sopenharmony_ci * be dropped soon. 33848c2ecf20Sopenharmony_ci */ 33858c2ecf20Sopenharmony_ci case NETDEV_TX_BUSY: 33868c2ecf20Sopenharmony_ci /* qdisc may call dev_hard_start_xmit directly in cases 33878c2ecf20Sopenharmony_ci * where no queues exist e.g. loopback device, virtual 33888c2ecf20Sopenharmony_ci * devices, etc. In this case we need to handle 33898c2ecf20Sopenharmony_ci * NETDEV_TX_ codes. 33908c2ecf20Sopenharmony_ci */ 33918c2ecf20Sopenharmony_ci default: 33928c2ecf20Sopenharmony_ci pkt_dev->errors++; 33938c2ecf20Sopenharmony_ci net_info_ratelimited("%s xmit error: %d\n", 33948c2ecf20Sopenharmony_ci pkt_dev->odevname, ret); 33958c2ecf20Sopenharmony_ci break; 33968c2ecf20Sopenharmony_ci } 33978c2ecf20Sopenharmony_ci goto out; 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci txq = skb_get_tx_queue(odev, pkt_dev->skb); 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci local_bh_disable(); 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci HARD_TX_LOCK(odev, txq, smp_processor_id()); 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) { 34078c2ecf20Sopenharmony_ci pkt_dev->last_ok = 0; 34088c2ecf20Sopenharmony_ci goto unlock; 34098c2ecf20Sopenharmony_ci } 34108c2ecf20Sopenharmony_ci refcount_add(burst, &pkt_dev->skb->users); 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_cixmit_more: 34138c2ecf20Sopenharmony_ci ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci switch (ret) { 34168c2ecf20Sopenharmony_ci case NETDEV_TX_OK: 34178c2ecf20Sopenharmony_ci pkt_dev->last_ok = 1; 34188c2ecf20Sopenharmony_ci pkt_dev->sofar++; 34198c2ecf20Sopenharmony_ci pkt_dev->seq_num++; 34208c2ecf20Sopenharmony_ci pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 34218c2ecf20Sopenharmony_ci if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq)) 34228c2ecf20Sopenharmony_ci goto xmit_more; 34238c2ecf20Sopenharmony_ci break; 34248c2ecf20Sopenharmony_ci case NET_XMIT_DROP: 34258c2ecf20Sopenharmony_ci case NET_XMIT_CN: 34268c2ecf20Sopenharmony_ci /* skb has been consumed */ 34278c2ecf20Sopenharmony_ci pkt_dev->errors++; 34288c2ecf20Sopenharmony_ci break; 34298c2ecf20Sopenharmony_ci default: /* Drivers are not supposed to return other values! */ 34308c2ecf20Sopenharmony_ci net_info_ratelimited("%s xmit error: %d\n", 34318c2ecf20Sopenharmony_ci pkt_dev->odevname, ret); 34328c2ecf20Sopenharmony_ci pkt_dev->errors++; 34338c2ecf20Sopenharmony_ci fallthrough; 34348c2ecf20Sopenharmony_ci case NETDEV_TX_BUSY: 34358c2ecf20Sopenharmony_ci /* Retry it next time */ 34368c2ecf20Sopenharmony_ci refcount_dec(&(pkt_dev->skb->users)); 34378c2ecf20Sopenharmony_ci pkt_dev->last_ok = 0; 34388c2ecf20Sopenharmony_ci } 34398c2ecf20Sopenharmony_ci if (unlikely(burst)) 34408c2ecf20Sopenharmony_ci WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users)); 34418c2ecf20Sopenharmony_ciunlock: 34428c2ecf20Sopenharmony_ci HARD_TX_UNLOCK(odev, txq); 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ciout: 34458c2ecf20Sopenharmony_ci local_bh_enable(); 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci /* If pkt_dev->count is zero, then run forever */ 34488c2ecf20Sopenharmony_ci if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 34498c2ecf20Sopenharmony_ci pktgen_wait_for_skb(pkt_dev); 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci /* Done with this */ 34528c2ecf20Sopenharmony_ci pktgen_stop_device(pkt_dev); 34538c2ecf20Sopenharmony_ci } 34548c2ecf20Sopenharmony_ci} 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci/* 34578c2ecf20Sopenharmony_ci * Main loop of the thread goes here 34588c2ecf20Sopenharmony_ci */ 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_cistatic int pktgen_thread_worker(void *arg) 34618c2ecf20Sopenharmony_ci{ 34628c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 34638c2ecf20Sopenharmony_ci struct pktgen_thread *t = arg; 34648c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev = NULL; 34658c2ecf20Sopenharmony_ci int cpu = t->cpu; 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci WARN_ON(smp_processor_id() != cpu); 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci init_waitqueue_head(&t->queue); 34708c2ecf20Sopenharmony_ci complete(&t->start_done); 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci set_freezable(); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 34778c2ecf20Sopenharmony_ci pkt_dev = next_to_run(t); 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci if (unlikely(!pkt_dev && t->control == 0)) { 34808c2ecf20Sopenharmony_ci if (t->net->pktgen_exiting) 34818c2ecf20Sopenharmony_ci break; 34828c2ecf20Sopenharmony_ci wait_event_interruptible_timeout(t->queue, 34838c2ecf20Sopenharmony_ci t->control != 0, 34848c2ecf20Sopenharmony_ci HZ/10); 34858c2ecf20Sopenharmony_ci try_to_freeze(); 34868c2ecf20Sopenharmony_ci continue; 34878c2ecf20Sopenharmony_ci } 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci if (likely(pkt_dev)) { 34908c2ecf20Sopenharmony_ci pktgen_xmit(pkt_dev); 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci if (need_resched()) 34938c2ecf20Sopenharmony_ci pktgen_resched(pkt_dev); 34948c2ecf20Sopenharmony_ci else 34958c2ecf20Sopenharmony_ci cpu_relax(); 34968c2ecf20Sopenharmony_ci } 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci if (t->control & T_STOP) { 34998c2ecf20Sopenharmony_ci pktgen_stop(t); 35008c2ecf20Sopenharmony_ci t->control &= ~(T_STOP); 35018c2ecf20Sopenharmony_ci } 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci if (t->control & T_RUN) { 35048c2ecf20Sopenharmony_ci pktgen_run(t); 35058c2ecf20Sopenharmony_ci t->control &= ~(T_RUN); 35068c2ecf20Sopenharmony_ci } 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci if (t->control & T_REMDEVALL) { 35098c2ecf20Sopenharmony_ci pktgen_rem_all_ifs(t); 35108c2ecf20Sopenharmony_ci t->control &= ~(T_REMDEVALL); 35118c2ecf20Sopenharmony_ci } 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci if (t->control & T_REMDEV) { 35148c2ecf20Sopenharmony_ci pktgen_rem_one_if(t); 35158c2ecf20Sopenharmony_ci t->control &= ~(T_REMDEV); 35168c2ecf20Sopenharmony_ci } 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci try_to_freeze(); 35198c2ecf20Sopenharmony_ci } 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci pr_debug("%s stopping all device\n", t->tsk->comm); 35228c2ecf20Sopenharmony_ci pktgen_stop(t); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci pr_debug("%s removing all device\n", t->tsk->comm); 35258c2ecf20Sopenharmony_ci pktgen_rem_all_ifs(t); 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci pr_debug("%s removing thread\n", t->tsk->comm); 35288c2ecf20Sopenharmony_ci pktgen_rem_thread(t); 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci return 0; 35318c2ecf20Sopenharmony_ci} 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_cistatic struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 35348c2ecf20Sopenharmony_ci const char *ifname, bool exact) 35358c2ecf20Sopenharmony_ci{ 35368c2ecf20Sopenharmony_ci struct pktgen_dev *p, *pkt_dev = NULL; 35378c2ecf20Sopenharmony_ci size_t len = strlen(ifname); 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci rcu_read_lock(); 35408c2ecf20Sopenharmony_ci list_for_each_entry_rcu(p, &t->if_list, list) 35418c2ecf20Sopenharmony_ci if (strncmp(p->odevname, ifname, len) == 0) { 35428c2ecf20Sopenharmony_ci if (p->odevname[len]) { 35438c2ecf20Sopenharmony_ci if (exact || p->odevname[len] != '@') 35448c2ecf20Sopenharmony_ci continue; 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci pkt_dev = p; 35478c2ecf20Sopenharmony_ci break; 35488c2ecf20Sopenharmony_ci } 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci rcu_read_unlock(); 35518c2ecf20Sopenharmony_ci pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 35528c2ecf20Sopenharmony_ci return pkt_dev; 35538c2ecf20Sopenharmony_ci} 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci/* 35568c2ecf20Sopenharmony_ci * Adds a dev at front of if_list. 35578c2ecf20Sopenharmony_ci */ 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_cistatic int add_dev_to_thread(struct pktgen_thread *t, 35608c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 35618c2ecf20Sopenharmony_ci{ 35628c2ecf20Sopenharmony_ci int rv = 0; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci /* This function cannot be called concurrently, as its called 35658c2ecf20Sopenharmony_ci * under pktgen_thread_lock mutex, but it can run from 35668c2ecf20Sopenharmony_ci * userspace on another CPU than the kthread. The if_lock() 35678c2ecf20Sopenharmony_ci * is used here to sync with concurrent instances of 35688c2ecf20Sopenharmony_ci * _rem_dev_from_if_list() invoked via kthread, which is also 35698c2ecf20Sopenharmony_ci * updating the if_list */ 35708c2ecf20Sopenharmony_ci if_lock(t); 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci if (pkt_dev->pg_thread) { 35738c2ecf20Sopenharmony_ci pr_err("ERROR: already assigned to a thread\n"); 35748c2ecf20Sopenharmony_ci rv = -EBUSY; 35758c2ecf20Sopenharmony_ci goto out; 35768c2ecf20Sopenharmony_ci } 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci pkt_dev->running = 0; 35798c2ecf20Sopenharmony_ci pkt_dev->pg_thread = t; 35808c2ecf20Sopenharmony_ci list_add_rcu(&pkt_dev->list, &t->if_list); 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ciout: 35838c2ecf20Sopenharmony_ci if_unlock(t); 35848c2ecf20Sopenharmony_ci return rv; 35858c2ecf20Sopenharmony_ci} 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci/* Called under thread lock */ 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_cistatic int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 35908c2ecf20Sopenharmony_ci{ 35918c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev; 35928c2ecf20Sopenharmony_ci int err; 35938c2ecf20Sopenharmony_ci int node = cpu_to_node(t->cpu); 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci /* We don't allow a device to be on several threads */ 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND); 35988c2ecf20Sopenharmony_ci if (pkt_dev) { 35998c2ecf20Sopenharmony_ci pr_err("ERROR: interface already used\n"); 36008c2ecf20Sopenharmony_ci return -EBUSY; 36018c2ecf20Sopenharmony_ci } 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 36048c2ecf20Sopenharmony_ci if (!pkt_dev) 36058c2ecf20Sopenharmony_ci return -ENOMEM; 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci strcpy(pkt_dev->odevname, ifname); 36088c2ecf20Sopenharmony_ci pkt_dev->flows = vzalloc_node(array_size(MAX_CFLOWS, 36098c2ecf20Sopenharmony_ci sizeof(struct flow_state)), 36108c2ecf20Sopenharmony_ci node); 36118c2ecf20Sopenharmony_ci if (pkt_dev->flows == NULL) { 36128c2ecf20Sopenharmony_ci kfree(pkt_dev); 36138c2ecf20Sopenharmony_ci return -ENOMEM; 36148c2ecf20Sopenharmony_ci } 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci pkt_dev->removal_mark = 0; 36178c2ecf20Sopenharmony_ci pkt_dev->nfrags = 0; 36188c2ecf20Sopenharmony_ci pkt_dev->delay = pg_delay_d; 36198c2ecf20Sopenharmony_ci pkt_dev->count = pg_count_d; 36208c2ecf20Sopenharmony_ci pkt_dev->sofar = 0; 36218c2ecf20Sopenharmony_ci pkt_dev->udp_src_min = 9; /* sink port */ 36228c2ecf20Sopenharmony_ci pkt_dev->udp_src_max = 9; 36238c2ecf20Sopenharmony_ci pkt_dev->udp_dst_min = 9; 36248c2ecf20Sopenharmony_ci pkt_dev->udp_dst_max = 9; 36258c2ecf20Sopenharmony_ci pkt_dev->vlan_p = 0; 36268c2ecf20Sopenharmony_ci pkt_dev->vlan_cfi = 0; 36278c2ecf20Sopenharmony_ci pkt_dev->vlan_id = 0xffff; 36288c2ecf20Sopenharmony_ci pkt_dev->svlan_p = 0; 36298c2ecf20Sopenharmony_ci pkt_dev->svlan_cfi = 0; 36308c2ecf20Sopenharmony_ci pkt_dev->svlan_id = 0xffff; 36318c2ecf20Sopenharmony_ci pkt_dev->burst = 1; 36328c2ecf20Sopenharmony_ci pkt_dev->node = NUMA_NO_NODE; 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_ci err = pktgen_setup_dev(t->net, pkt_dev, ifname); 36358c2ecf20Sopenharmony_ci if (err) 36368c2ecf20Sopenharmony_ci goto out1; 36378c2ecf20Sopenharmony_ci if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) 36388c2ecf20Sopenharmony_ci pkt_dev->clone_skb = pg_clone_skb_d; 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir, 36418c2ecf20Sopenharmony_ci &pktgen_if_proc_ops, pkt_dev); 36428c2ecf20Sopenharmony_ci if (!pkt_dev->entry) { 36438c2ecf20Sopenharmony_ci pr_err("cannot create %s/%s procfs entry\n", 36448c2ecf20Sopenharmony_ci PG_PROC_DIR, ifname); 36458c2ecf20Sopenharmony_ci err = -EINVAL; 36468c2ecf20Sopenharmony_ci goto out2; 36478c2ecf20Sopenharmony_ci } 36488c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 36498c2ecf20Sopenharmony_ci pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 36508c2ecf20Sopenharmony_ci pkt_dev->ipsproto = IPPROTO_ESP; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci /* xfrm tunnel mode needs additional dst to extract outter 36538c2ecf20Sopenharmony_ci * ip header protocol/ttl/id field, here creat a phony one. 36548c2ecf20Sopenharmony_ci * instead of looking for a valid rt, which definitely hurting 36558c2ecf20Sopenharmony_ci * performance under such circumstance. 36568c2ecf20Sopenharmony_ci */ 36578c2ecf20Sopenharmony_ci pkt_dev->dstops.family = AF_INET; 36588c2ecf20Sopenharmony_ci pkt_dev->xdst.u.dst.dev = pkt_dev->odev; 36598c2ecf20Sopenharmony_ci dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false); 36608c2ecf20Sopenharmony_ci pkt_dev->xdst.child = &pkt_dev->xdst.u.dst; 36618c2ecf20Sopenharmony_ci pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops; 36628c2ecf20Sopenharmony_ci#endif 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci return add_dev_to_thread(t, pkt_dev); 36658c2ecf20Sopenharmony_ciout2: 36668c2ecf20Sopenharmony_ci dev_put(pkt_dev->odev); 36678c2ecf20Sopenharmony_ciout1: 36688c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 36698c2ecf20Sopenharmony_ci free_SAs(pkt_dev); 36708c2ecf20Sopenharmony_ci#endif 36718c2ecf20Sopenharmony_ci vfree(pkt_dev->flows); 36728c2ecf20Sopenharmony_ci kfree(pkt_dev); 36738c2ecf20Sopenharmony_ci return err; 36748c2ecf20Sopenharmony_ci} 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_cistatic int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) 36778c2ecf20Sopenharmony_ci{ 36788c2ecf20Sopenharmony_ci struct pktgen_thread *t; 36798c2ecf20Sopenharmony_ci struct proc_dir_entry *pe; 36808c2ecf20Sopenharmony_ci struct task_struct *p; 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 36838c2ecf20Sopenharmony_ci cpu_to_node(cpu)); 36848c2ecf20Sopenharmony_ci if (!t) { 36858c2ecf20Sopenharmony_ci pr_err("ERROR: out of memory, can't create new thread\n"); 36868c2ecf20Sopenharmony_ci return -ENOMEM; 36878c2ecf20Sopenharmony_ci } 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci mutex_init(&t->if_lock); 36908c2ecf20Sopenharmony_ci t->cpu = cpu; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&t->if_list); 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci list_add_tail(&t->th_list, &pn->pktgen_threads); 36958c2ecf20Sopenharmony_ci init_completion(&t->start_done); 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci p = kthread_create_on_node(pktgen_thread_worker, 36988c2ecf20Sopenharmony_ci t, 36998c2ecf20Sopenharmony_ci cpu_to_node(cpu), 37008c2ecf20Sopenharmony_ci "kpktgend_%d", cpu); 37018c2ecf20Sopenharmony_ci if (IS_ERR(p)) { 37028c2ecf20Sopenharmony_ci pr_err("kthread_create_on_node() failed for cpu %d\n", t->cpu); 37038c2ecf20Sopenharmony_ci list_del(&t->th_list); 37048c2ecf20Sopenharmony_ci kfree(t); 37058c2ecf20Sopenharmony_ci return PTR_ERR(p); 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci kthread_bind(p, cpu); 37088c2ecf20Sopenharmony_ci t->tsk = p; 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir, 37118c2ecf20Sopenharmony_ci &pktgen_thread_proc_ops, t); 37128c2ecf20Sopenharmony_ci if (!pe) { 37138c2ecf20Sopenharmony_ci pr_err("cannot create %s/%s procfs entry\n", 37148c2ecf20Sopenharmony_ci PG_PROC_DIR, t->tsk->comm); 37158c2ecf20Sopenharmony_ci kthread_stop(p); 37168c2ecf20Sopenharmony_ci list_del(&t->th_list); 37178c2ecf20Sopenharmony_ci kfree(t); 37188c2ecf20Sopenharmony_ci return -EINVAL; 37198c2ecf20Sopenharmony_ci } 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci t->net = pn; 37228c2ecf20Sopenharmony_ci get_task_struct(p); 37238c2ecf20Sopenharmony_ci wake_up_process(p); 37248c2ecf20Sopenharmony_ci wait_for_completion(&t->start_done); 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_ci return 0; 37278c2ecf20Sopenharmony_ci} 37288c2ecf20Sopenharmony_ci 37298c2ecf20Sopenharmony_ci/* 37308c2ecf20Sopenharmony_ci * Removes a device from the thread if_list. 37318c2ecf20Sopenharmony_ci */ 37328c2ecf20Sopenharmony_cistatic void _rem_dev_from_if_list(struct pktgen_thread *t, 37338c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 37348c2ecf20Sopenharmony_ci{ 37358c2ecf20Sopenharmony_ci struct list_head *q, *n; 37368c2ecf20Sopenharmony_ci struct pktgen_dev *p; 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci if_lock(t); 37398c2ecf20Sopenharmony_ci list_for_each_safe(q, n, &t->if_list) { 37408c2ecf20Sopenharmony_ci p = list_entry(q, struct pktgen_dev, list); 37418c2ecf20Sopenharmony_ci if (p == pkt_dev) 37428c2ecf20Sopenharmony_ci list_del_rcu(&p->list); 37438c2ecf20Sopenharmony_ci } 37448c2ecf20Sopenharmony_ci if_unlock(t); 37458c2ecf20Sopenharmony_ci} 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_cistatic int pktgen_remove_device(struct pktgen_thread *t, 37488c2ecf20Sopenharmony_ci struct pktgen_dev *pkt_dev) 37498c2ecf20Sopenharmony_ci{ 37508c2ecf20Sopenharmony_ci pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci if (pkt_dev->running) { 37538c2ecf20Sopenharmony_ci pr_warn("WARNING: trying to remove a running interface, stopping it now\n"); 37548c2ecf20Sopenharmony_ci pktgen_stop_device(pkt_dev); 37558c2ecf20Sopenharmony_ci } 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci /* Dis-associate from the interface */ 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci if (pkt_dev->odev) { 37608c2ecf20Sopenharmony_ci dev_put(pkt_dev->odev); 37618c2ecf20Sopenharmony_ci pkt_dev->odev = NULL; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci /* Remove proc before if_list entry, because add_device uses 37658c2ecf20Sopenharmony_ci * list to determine if interface already exist, avoid race 37668c2ecf20Sopenharmony_ci * with proc_create_data() */ 37678c2ecf20Sopenharmony_ci proc_remove(pkt_dev->entry); 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci /* And update the thread if_list */ 37708c2ecf20Sopenharmony_ci _rem_dev_from_if_list(t, pkt_dev); 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 37738c2ecf20Sopenharmony_ci free_SAs(pkt_dev); 37748c2ecf20Sopenharmony_ci#endif 37758c2ecf20Sopenharmony_ci vfree(pkt_dev->flows); 37768c2ecf20Sopenharmony_ci if (pkt_dev->page) 37778c2ecf20Sopenharmony_ci put_page(pkt_dev->page); 37788c2ecf20Sopenharmony_ci kfree_rcu(pkt_dev, rcu); 37798c2ecf20Sopenharmony_ci return 0; 37808c2ecf20Sopenharmony_ci} 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_cistatic int __net_init pg_net_init(struct net *net) 37838c2ecf20Sopenharmony_ci{ 37848c2ecf20Sopenharmony_ci struct pktgen_net *pn = net_generic(net, pg_net_id); 37858c2ecf20Sopenharmony_ci struct proc_dir_entry *pe; 37868c2ecf20Sopenharmony_ci int cpu, ret = 0; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci pn->net = net; 37898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pn->pktgen_threads); 37908c2ecf20Sopenharmony_ci pn->pktgen_exiting = false; 37918c2ecf20Sopenharmony_ci pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net); 37928c2ecf20Sopenharmony_ci if (!pn->proc_dir) { 37938c2ecf20Sopenharmony_ci pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); 37948c2ecf20Sopenharmony_ci return -ENODEV; 37958c2ecf20Sopenharmony_ci } 37968c2ecf20Sopenharmony_ci pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_proc_ops); 37978c2ecf20Sopenharmony_ci if (pe == NULL) { 37988c2ecf20Sopenharmony_ci pr_err("cannot create %s procfs entry\n", PGCTRL); 37998c2ecf20Sopenharmony_ci ret = -EINVAL; 38008c2ecf20Sopenharmony_ci goto remove; 38018c2ecf20Sopenharmony_ci } 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci for_each_online_cpu(cpu) { 38048c2ecf20Sopenharmony_ci int err; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci err = pktgen_create_thread(cpu, pn); 38078c2ecf20Sopenharmony_ci if (err) 38088c2ecf20Sopenharmony_ci pr_warn("Cannot create thread for cpu %d (%d)\n", 38098c2ecf20Sopenharmony_ci cpu, err); 38108c2ecf20Sopenharmony_ci } 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci if (list_empty(&pn->pktgen_threads)) { 38138c2ecf20Sopenharmony_ci pr_err("Initialization failed for all threads\n"); 38148c2ecf20Sopenharmony_ci ret = -ENODEV; 38158c2ecf20Sopenharmony_ci goto remove_entry; 38168c2ecf20Sopenharmony_ci } 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci return 0; 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ciremove_entry: 38218c2ecf20Sopenharmony_ci remove_proc_entry(PGCTRL, pn->proc_dir); 38228c2ecf20Sopenharmony_ciremove: 38238c2ecf20Sopenharmony_ci remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 38248c2ecf20Sopenharmony_ci return ret; 38258c2ecf20Sopenharmony_ci} 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_cistatic void __net_exit pg_net_exit(struct net *net) 38288c2ecf20Sopenharmony_ci{ 38298c2ecf20Sopenharmony_ci struct pktgen_net *pn = net_generic(net, pg_net_id); 38308c2ecf20Sopenharmony_ci struct pktgen_thread *t; 38318c2ecf20Sopenharmony_ci struct list_head *q, *n; 38328c2ecf20Sopenharmony_ci LIST_HEAD(list); 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci /* Stop all interfaces & threads */ 38358c2ecf20Sopenharmony_ci pn->pktgen_exiting = true; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci mutex_lock(&pktgen_thread_lock); 38388c2ecf20Sopenharmony_ci list_splice_init(&pn->pktgen_threads, &list); 38398c2ecf20Sopenharmony_ci mutex_unlock(&pktgen_thread_lock); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci list_for_each_safe(q, n, &list) { 38428c2ecf20Sopenharmony_ci t = list_entry(q, struct pktgen_thread, th_list); 38438c2ecf20Sopenharmony_ci list_del(&t->th_list); 38448c2ecf20Sopenharmony_ci kthread_stop(t->tsk); 38458c2ecf20Sopenharmony_ci put_task_struct(t->tsk); 38468c2ecf20Sopenharmony_ci kfree(t); 38478c2ecf20Sopenharmony_ci } 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci remove_proc_entry(PGCTRL, pn->proc_dir); 38508c2ecf20Sopenharmony_ci remove_proc_entry(PG_PROC_DIR, pn->net->proc_net); 38518c2ecf20Sopenharmony_ci} 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_cistatic struct pernet_operations pg_net_ops = { 38548c2ecf20Sopenharmony_ci .init = pg_net_init, 38558c2ecf20Sopenharmony_ci .exit = pg_net_exit, 38568c2ecf20Sopenharmony_ci .id = &pg_net_id, 38578c2ecf20Sopenharmony_ci .size = sizeof(struct pktgen_net), 38588c2ecf20Sopenharmony_ci}; 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_cistatic int __init pg_init(void) 38618c2ecf20Sopenharmony_ci{ 38628c2ecf20Sopenharmony_ci int ret = 0; 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci pr_info("%s", version); 38658c2ecf20Sopenharmony_ci ret = register_pernet_subsys(&pg_net_ops); 38668c2ecf20Sopenharmony_ci if (ret) 38678c2ecf20Sopenharmony_ci return ret; 38688c2ecf20Sopenharmony_ci ret = register_netdevice_notifier(&pktgen_notifier_block); 38698c2ecf20Sopenharmony_ci if (ret) 38708c2ecf20Sopenharmony_ci unregister_pernet_subsys(&pg_net_ops); 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci return ret; 38738c2ecf20Sopenharmony_ci} 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_cistatic void __exit pg_cleanup(void) 38768c2ecf20Sopenharmony_ci{ 38778c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&pktgen_notifier_block); 38788c2ecf20Sopenharmony_ci unregister_pernet_subsys(&pg_net_ops); 38798c2ecf20Sopenharmony_ci /* Don't need rcu_barrier() due to use of kfree_rcu() */ 38808c2ecf20Sopenharmony_ci} 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_cimodule_init(pg_init); 38838c2ecf20Sopenharmony_cimodule_exit(pg_cleanup); 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 38868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Packet Generator tool"); 38878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 38888c2ecf20Sopenharmony_ciMODULE_VERSION(VERSION); 38898c2ecf20Sopenharmony_cimodule_param(pg_count_d, int, 0); 38908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 38918c2ecf20Sopenharmony_cimodule_param(pg_delay_d, int, 0); 38928c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 38938c2ecf20Sopenharmony_cimodule_param(pg_clone_skb_d, int, 0); 38948c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 38958c2ecf20Sopenharmony_cimodule_param(debug, int, 0); 38968c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3897