⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pktgen.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 + -