📄 pktgen.c
字号:
/* * Authors: * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> * Uppsala University and * Swedish University of Agricultural Sciences * * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * Ben Greear <greearb@candelatech.com> * Jens Låås <jens.laas@data.slu.se> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * * A tool for loading the network with preconfigurated packets. * The tool is implemented as a linux module. Parameters are output * device, delay (to hard_xmit), number of packets, and whether * to use multiple SKBs or just the same one. * pktgen uses the installed interface's output routine. * * Additional hacking by: * * Jens.Laas@data.slu.se * Improved by ANK. 010120. * Improved by ANK even more. 010212. * MAC address typo fixed. 010417 --ro * Integrated. 020301 --DaveM * Added multiskb option 020301 --DaveM * Scaling of results. 020417--sigurdur@linpro.no * Significant re-work of the module: * * Convert to threaded model to more efficiently be able to transmit * and receive on multiple interfaces at once. * * Converted many counters to __u64 to allow longer runs. * * Allow configuration of ranges, like min/max IP address, MACs, * and UDP-ports, for both source and destination, and can * set to use a random distribution or sequentially walk the range. * * Can now change most values after starting. * * Place 12-byte packet in UDP payload with magic number, * sequence number, and timestamp. * * Add receiver code that detects dropped pkts, re-ordered pkts, and * latencies (with micro-second) precision. * * Add IOCTL interface to easily get counters & configuration. * --Ben Greear <greearb@candelatech.com> * * Renamed multiskb to clone_skb and cleaned up sending core for two distinct * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 * as a "fastpath" with a configurable number of clones after alloc's. * clone_skb=0 means all packets are allocated this also means ranges time * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 * clones. * * Also moved to /proc/net/pktgen/ * --ro * * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever * mistakes. Also merged in DaveM's patch in the -pre6 patch. * --Ben Greear <greearb@candelatech.com> * * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) * * * 021124 Finished major redesign and rewrite for new functionality. * See Documentation/networking/pktgen.txt for how to use this. * * The new operation: * For each CPU one thread/process is created at start. This process checks * for running devices in the if_list and sends packets until count is 0 it * also the thread checks the thread->control which is used for inter-process * communication. controlling process "posts" operations to the threads this * way. The if_lock should be possible to remove when add/rem_device is merged * into this too. * * By design there should only be *one* "controlling" process. In practice * multiple write accesses gives unpredictable result. Understood by "write" * to /proc gives result code thats should be read be the "writer". * For practical use this should be no problem. * * Note when adding devices to a specific CPU there good idea to also assign * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. * --ro * * Fix refcount off by one if first packet fails, potential null deref, * memleak 030710- KJP * * First "ranges" functionality for ipv6 030726 --ro * * Included flow support. 030802 ANK. * * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> * * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 * * New xmit() return, do_div and misc clean up by Stephen Hemminger * <shemminger@osdl.org> 040923 * * Randy Dunlap fixed u64 printk compiler waring * * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 * * Corrections from Nikolai Malykh (nmalykh@bilim.com) * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 * * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> * 050103 * * MPLS support by Steven Whitehouse <steve@chygwyn.com> * * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> * * Fixed src_mac command to set source mac of packet to value specified in * command by Adit Ranadive <adit.262@gmail.com> * */#include <linux/sys.h>#include <linux/types.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/mutex.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/unistd.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/capability.h>#include <linux/freezer.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/inet.h>#include <linux/inetdevice.h>#include <linux/rtnetlink.h>#include <linux/if_arp.h>#include <linux/if_vlan.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/ipv6.h>#include <linux/udp.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/wait.h>#include <linux/etherdevice.h>#include <linux/kthread.h>#include <net/net_namespace.h>#include <net/checksum.h>#include <net/ipv6.h>#include <net/addrconf.h>#ifdef CONFIG_XFRM#include <net/xfrm.h>#endif#include <asm/byteorder.h>#include <linux/rcupdate.h>#include <linux/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <asm/div64.h> /* do_div */#include <asm/timex.h>#define VERSION "pktgen v2.69: Packet Generator for packet performance testing.\n"/* The buckets are exponential in 'width' */#define LAT_BUCKETS_MAX 32#define IP_NAME_SZ 32#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */#define MPLS_STACK_BOTTOM htonl(0x00000100)/* Device flag bits */#define F_IPSRC_RND (1<<0) /* IP-Src Random */#define F_IPDST_RND (1<<1) /* IP-Dst Random */#define F_UDPSRC_RND (1<<2) /* UDP-Src Random */#define F_UDPDST_RND (1<<3) /* UDP-Dst Random */#define F_MACSRC_RND (1<<4) /* MAC-Src Random */#define F_MACDST_RND (1<<5) /* MAC-Dst Random */#define F_TXSIZE_RND (1<<6) /* Transmit size is random */#define F_IPV6 (1<<7) /* Interface in IPV6 Mode */#define F_MPLS_RND (1<<8) /* Random MPLS labels */#define F_VID_RND (1<<9) /* Random VLAN ID */#define F_SVID_RND (1<<10) /* Random SVLAN ID */#define F_FLOW_SEQ (1<<11) /* Sequential flows */#define F_IPSEC_ON (1<<12) /* ipsec on for flows */#define F_QUEUE_MAP_RND (1<<13) /* queue map Random *//* Thread control flag bits */#define T_TERMINATE (1<<0)#define T_STOP (1<<1) /* Stop run */#define T_RUN (1<<2) /* Start run */#define T_REMDEVALL (1<<3) /* Remove all devs */#define T_REMDEV (1<<4) /* Remove one dev *//* If lock -- can be removed after some work */#define if_lock(t) spin_lock(&(t->if_lock));#define if_unlock(t) spin_unlock(&(t->if_lock));/* Used to help with determining the pkts on receive */#define PKTGEN_MAGIC 0xbe9be955#define PG_PROC_DIR "pktgen"#define PGCTRL "pgctrl"static struct proc_dir_entry *pg_proc_dir = NULL;#define MAX_CFLOWS 65536#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)struct flow_state { __be32 cur_daddr; int count;#ifdef CONFIG_XFRM struct xfrm_state *x;#endif __u32 flags;};/* flow flag bits */#define F_INIT (1<<0) /* flow has been initialized */struct pktgen_dev { /* * Try to keep frequent/infrequent used vars. separated. */ struct proc_dir_entry *entry; /* proc file */ struct pktgen_thread *pg_thread;/* the owner */ struct list_head list; /* Used for chaining in the thread's run-queue */ int running; /* if this changes to false, the test will stop */ /* If min != max, then we will either do a linear iteration, or * we will do a random selection from within the range. */ __u32 flags; int removal_mark; /* non-zero => the device is marked for * removal by worker thread */ int min_pkt_size; /* = ETH_ZLEN; */ int max_pkt_size; /* = ETH_ZLEN; */ int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ int nfrags; __u32 delay_us; /* Default delay */ __u32 delay_ns; __u64 count; /* Default No packets to send */ __u64 sofar; /* How many pkts we've sent so far */ __u64 tx_bytes; /* How many bytes we've transmitted */ __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ /* runtime counters relating to clone_skb */ __u64 next_tx_us; /* timestamp of when to tx next */ __u32 next_tx_ns; __u64 allocated_skbs; __u32 clone_count; int last_ok; /* Was last skb sent? * Or a failed transmit of some sort? This will keep * sequence numbers in order, for example. */ __u64 started_at; /* micro-seconds */ __u64 stopped_at; /* micro-seconds */ __u64 idle_acc; /* micro-seconds */ __u32 seq_num; int clone_skb; /* Use multiple SKBs during packet gen. If this number * is greater than 1, then that many copies of the same * packet will be sent before a new packet is allocated. * For instance, if you want to send 1024 identical packets * before creating a new packet, set clone_skb to 1024. */ char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ struct in6_addr in6_saddr; struct in6_addr in6_daddr; struct in6_addr cur_in6_daddr; struct in6_addr cur_in6_saddr; /* For ranges */ struct in6_addr min_in6_daddr; struct in6_addr max_in6_daddr; struct in6_addr min_in6_saddr; struct in6_addr max_in6_saddr; /* If we're doing ranges, random or incremental, then this * defines the min/max for those ranges. */ __be32 saddr_min; /* inclusive, source IP address */ __be32 saddr_max; /* exclusive, source IP address */ __be32 daddr_min; /* inclusive, dest IP address */ __be32 daddr_max; /* exclusive, dest IP address */ __u16 udp_src_min; /* inclusive, source UDP port */ __u16 udp_src_max; /* exclusive, source UDP port */ __u16 udp_dst_min; /* inclusive, dest UDP port */ __u16 udp_dst_max; /* exclusive, dest UDP port */ /* DSCP + ECN */ __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */ __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */ /* MPLS */ unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ __be32 labels[MAX_MPLS_LABELS]; /* VLAN/SVLAN (802.1Q/Q-in-Q) */ __u8 vlan_p; __u8 vlan_cfi; __u16 vlan_id; /* 0xffff means no vlan tag */ __u8 svlan_p; __u8 svlan_cfi; __u16 svlan_id; /* 0xffff means no svlan tag */ __u32 src_mac_count; /* How many MACs to iterate through */ __u32 dst_mac_count; /* How many MACs to iterate through */ unsigned char dst_mac[ETH_ALEN]; unsigned char src_mac[ETH_ALEN]; __u32 cur_dst_mac_offset; __u32 cur_src_mac_offset; __be32 cur_saddr; __be32 cur_daddr; __u16 cur_udp_dst; __u16 cur_udp_src; __u16 cur_queue_map; __u32 cur_pkt_size; __u8 hh[14]; /* = { 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, We fill in SRC address later 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 }; */ __u16 pad; /* pad out the hh struct to an even 16 bytes */ struct sk_buff *skb; /* skb we are to transmit next, mainly used for when we * are transmitting the same one multiple times */ struct net_device *odev; /* The out-going device. Note that the device should * have it's pg_info pointer pointing back to this * device. This will be set when the user specifies * the out-going device name (not when the inject is * started as it used to do.) */ struct flow_state *flows; unsigned cflows; /* Concurrent flows (config) */ unsigned lflow; /* Flow length (config) */ unsigned nflows; /* accumulated flows (stats) */ unsigned curfl; /* current sequenced flow (state)*/ u16 queue_map_min; u16 queue_map_max;#ifdef CONFIG_XFRM __u8 ipsmode; /* IPSEC mode (config) */ __u8 ipsproto; /* IPSEC type (config) */#endif char result[512];};struct pktgen_hdr { __be32 pgh_magic; __be32 seq_num; __be32 tv_sec; __be32 tv_usec;};struct pktgen_thread { spinlock_t if_lock; struct list_head if_list; /* All device here */ struct list_head th_list; struct task_struct *tsk; char result[512]; /* Field for thread to receive "posted" events terminate, stop ifs etc. */ u32 control; int cpu; wait_queue_head_t queue;};#define REMOVE 1#define FIND 0/* This code works around the fact that do_div cannot handle two 64-bit numbers, and regular 64-bit division doesn't work on x86 kernels. --Ben*/#define PG_DIV 0/* This was emailed to LMKL by: Chris Caputo <ccaputo@alt.net> * Function copied/adapted/optimized from: * * nemesis.sourceforge.net/browse/lib/static/intmath/ix86/intmath.c.html * * Copyright 1994, University of Cambridge Computer Laboratory * All Rights Reserved. * */static inline s64 divremdi3(s64 x, s64 y, int type){ u64 a = (x < 0) ? -x : x; u64 b = (y < 0) ? -y : y; u64 res = 0, d = 1; if (b > 0) { while (b < a) { b <<= 1; d <<= 1; } } do { if (a >= b) { a -= b; res += d; } b >>= 1; d >>= 1; } while (d); if (PG_DIV == type) { return (((x ^ y) & (1ll << 63)) == 0) ? res : -(s64) res; } else { return ((x & (1ll << 63)) == 0) ? a : -(s64) a; }}/* End of hacks to deal with 64-bit math on x86 *//** Convert to milliseconds */static inline __u64 tv_to_ms(const struct timeval *tv){ __u64 ms = tv->tv_usec / 1000; ms += (__u64) tv->tv_sec * (__u64) 1000; return ms;}/** Convert to micro-seconds */static inline __u64 tv_to_us(const struct timeval *tv){ __u64 us = tv->tv_usec; us += (__u64) tv->tv_sec * (__u64) 1000000; return us;}static inline __u64 pg_div(__u64 n, __u32 base){ __u64 tmp = n; do_div(tmp, base); /* printk("pktgen: pg_div, n: %llu base: %d rv: %llu\n", n, base, tmp); */ return tmp;}static inline __u64 pg_div64(__u64 n, __u64 base){ __u64 tmp = n;/* * How do we know if the architecture we are running on * supports division with 64 bit base? * */#if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__) do_div(tmp, base);#else tmp = divremdi3(n, base, PG_DIV);#endif return tmp;}static inline __u64 getCurMs(void){ struct timeval tv; do_gettimeofday(&tv); return tv_to_ms(&tv);}static inline __u64 getCurUs(void){ struct timeval tv; do_gettimeofday(&tv); return tv_to_us(&tv);}static inline __u64 tv_diff(const struct timeval *a, const struct timeval *b){ return tv_to_us(a) - tv_to_us(b);}/* old include end */static char version[] __initdata = VERSION;static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char *ifname);static int pktgen_device_event(struct notifier_block *, unsigned long, void *);static void pktgen_run_all_threads(void);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -