📄 pktgen.c
字号:
/* -*-linux-c-*- * $Id: pktgen.c,v 1.8 2002/07/15 19:30:17 robert Exp $ * pktgen.c: Packet Generator for performance evaluation. * * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> * Uppsala University, Sweden * * A tool for loading the network with preconfigurated packets. * The tool is implemented as a linux module. Parameters are output * device, IPG (interpacket gap), 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: * * Updated to support generation over multiple interfaces at once * by creating 32 /proc/net/pg* files. Each file can be manipulated * individually. * * 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 some values after starting. * * Place 12-byte packet in UDP payload with magic number, * sequence number, and timestamp. Will write receiver next. * * The new changes seem to have a performance impact of around 1%, * as far as I can tell. * --Ben Greear <greearb@candelatech.com> * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) * * 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 * * Fix refcount off by one if first packet fails, potential null deref, * memleak 030710- KJP * * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> * * New xmit() return, do_div and misc clean up by Stephen Hemminger * <shemminger@osdl.org> 040923 * * See Documentation/networking/pktgen.txt for how to use this. */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/inet.h>#include <linux/rcupdate.h>#include <asm/byteorder.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/udp.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/rtnetlink.h>#include <linux/proc_fs.h>#include <linux/if_arp.h>#include <net/checksum.h>#include <asm/timex.h>#define cycles() ((u32)get_cycles())#define VERSION "pktgen version 1.32"static char version[] __initdata = "pktgen.c: v1.4: Packet Generator for packet performance testing.\n";/* Used to help with determining the pkts on receive */#define PKTGEN_MAGIC 0xbe9be955/* Keep information per interface */struct pktgen_info { /* Parameters */ /* If min != max, then we will either do a linear iteration, or * we will do a random selection from within the range. */ __u32 flags; #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_SET_SRCMAC (1<<6) /* Specify-Src-Mac (default is to use Interface's MAC Addr) */#define F_SET_SRCIP (1<<7) /* Specify-Src-IP (default is to use Interface's IP Addr) */ int pkt_size; /* = ETH_ZLEN; */ int nfrags; __u32 ipg; /* Default Interpacket gap in nsec */ __u64 count; /* Default No packets to send */ __u64 sofar; /* How many pkts we've sent so far */ __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ struct timeval started_at; struct timeval stopped_at; __u64 idle_acc; __u32 seq_num; int clone_skb; /* Use multiple SKBs during packet gen. If this number * is greater than 1, then that many coppies 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. */ int busy; int do_run_run; /* if this changes to false, the test will stop */ char outdev[32]; char dst_min[32]; char dst_max[32]; char src_min[32]; char src_max[32]; /* If we're doing ranges, random or incremental, then this * defines the min/max for those ranges. */ __u32 saddr_min; /* inclusive, source IP address */ __u32 saddr_max; /* exclusive, source IP address */ __u32 daddr_min; /* inclusive, dest IP address */ __u32 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 */ __u32 src_mac_count; /* How many MACs to iterate through */ __u32 dst_mac_count; /* How many MACs to iterate through */ unsigned char dst_mac[6]; unsigned char src_mac[6]; __u32 cur_dst_mac_offset; __u32 cur_src_mac_offset; __u32 cur_saddr; __u32 cur_daddr; __u16 cur_udp_dst; __u16 cur_udp_src; __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 */ char result[512]; /* proc file names */ char fname[80]; char busy_fname[80]; struct proc_dir_entry *proc_ent; struct proc_dir_entry *busy_proc_ent;};struct pktgen_hdr { __u32 pgh_magic; __u32 seq_num; __u32 tv_sec; __u32 tv_usec;};static int cpu_speed;static int debug;/* Module parameters, defaults. */static int count_d = 100000;static int ipg_d;static int clone_skb_d;#define MAX_PKTGEN 8static struct pktgen_info pginfos[MAX_PKTGEN];/** Convert to miliseconds */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;}static inline __u64 getCurMs(void) { struct timeval tv; do_gettimeofday(&tv); return tv_to_ms(&tv);}#define PG_PROC_DIR "pktgen"static struct proc_dir_entry *proc_dir;static struct net_device *setup_inject(struct pktgen_info* info){ struct net_device *odev; odev = dev_get_by_name(info->outdev); if (!odev) { sprintf(info->result, "No such netdevice: \"%s\"", info->outdev); goto out; } if (odev->type != ARPHRD_ETHER) { sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev); goto out_put; } if (!netif_running(odev)) { sprintf(info->result, "Device is down: \"%s\"", info->outdev); goto out_put; } /* Default to the interface's mac if not explicitly set. */ if (!(info->flags & F_SET_SRCMAC)) { memcpy(&(info->hh[6]), odev->dev_addr, 6); } else { memcpy(&(info->hh[6]), info->src_mac, 6); } /* Set up Dest MAC */ memcpy(&(info->hh[0]), info->dst_mac, 6); info->saddr_min = 0; info->saddr_max = 0; if (strlen(info->src_min) == 0) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get(odev); if (in_dev) { if (in_dev->ifa_list) { info->saddr_min = in_dev->ifa_list->ifa_address; info->saddr_max = info->saddr_min; } } rcu_read_unlock(); } else { info->saddr_min = in_aton(info->src_min); info->saddr_max = in_aton(info->src_max); } info->daddr_min = in_aton(info->dst_min); info->daddr_max = in_aton(info->dst_max); /* Initialize current values. */ info->cur_dst_mac_offset = 0; info->cur_src_mac_offset = 0; info->cur_saddr = info->saddr_min; info->cur_daddr = info->daddr_min; info->cur_udp_dst = info->udp_dst_min; info->cur_udp_src = info->udp_src_min; return odev;out_put: dev_put(odev);out: return NULL;}static void nanospin(int ipg, struct pktgen_info* info){ u32 idle_start, idle; idle_start = cycles(); for (;;) { barrier(); idle = cycles() - idle_start; if (idle * 1000 >= ipg * cpu_speed) break; } info->idle_acc += idle;}static int calc_mhz(void){ struct timeval start, stop; u32 start_s, elapsed; do_gettimeofday(&start); start_s = cycles(); do { barrier(); elapsed = cycles() - start_s; if (elapsed == 0) return 0; } while (elapsed < 1000 * 50000); do_gettimeofday(&stop); return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));}static void cycles_calibrate(void){ int i; for (i = 0; i < 3; i++) { int res = calc_mhz(); if (res > cpu_speed) cpu_speed = res; }}/* Increment/randomize headers according to flags and current values * for IP src/dest, UDP src/dst port, MAC-Addr src/dst */static void mod_cur_headers(struct pktgen_info* info) { __u32 imn; __u32 imx; /* Deal with source MAC */ if (info->src_mac_count > 1) { __u32 mc; __u32 tmp; if (info->flags & F_MACSRC_RND) { mc = net_random() % (info->src_mac_count); } else { mc = info->cur_src_mac_offset++; if (info->cur_src_mac_offset > info->src_mac_count) { info->cur_src_mac_offset = 0; } } tmp = info->src_mac[5] + (mc & 0xFF); info->hh[11] = tmp; tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); info->hh[10] = tmp; tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); info->hh[9] = tmp; tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); info->hh[8] = tmp; tmp = (info->src_mac[1] + (tmp >> 8)); info->hh[7] = tmp; } /* Deal with Destination MAC */ if (info->dst_mac_count > 1) { __u32 mc; __u32 tmp; if (info->flags & F_MACDST_RND) { mc = net_random() % (info->dst_mac_count); } else { mc = info->cur_dst_mac_offset++; if (info->cur_dst_mac_offset > info->dst_mac_count) { info->cur_dst_mac_offset = 0; } } tmp = info->dst_mac[5] + (mc & 0xFF); info->hh[5] = tmp; tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); info->hh[4] = tmp; tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); info->hh[3] = tmp; tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); info->hh[2] = tmp; tmp = (info->dst_mac[1] + (tmp >> 8)); info->hh[1] = tmp; } if (info->udp_src_min < info->udp_src_max) { if (info->flags & F_UDPSRC_RND) { info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min)) + info->udp_src_min); } else { info->cur_udp_src++; if (info->cur_udp_src >= info->udp_src_max) { info->cur_udp_src = info->udp_src_min; } } } if (info->udp_dst_min < info->udp_dst_max) { if (info->flags & F_UDPDST_RND) { info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min)) + info->udp_dst_min); } else { info->cur_udp_dst++; if (info->cur_udp_dst >= info->udp_dst_max) { info->cur_udp_dst = info->udp_dst_min; } } } if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) { __u32 t; if (info->flags & F_IPSRC_RND) { t = ((net_random() % (imx - imn)) + imn); } else { t = ntohl(info->cur_saddr); t++; if (t >= imx) { t = imn; } } info->cur_saddr = htonl(t); } if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) { __u32 t; if (info->flags & F_IPDST_RND) { t = ((net_random() % (imx - imn)) + imn); } else { t = ntohl(info->cur_daddr); t++; if (t >= imx) { t = imn; } } info->cur_daddr = htonl(t); }}/* mod_cur_headers */static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info){ struct sk_buff *skb = NULL; __u8 *eth; struct udphdr *udph; int datalen, iplen; struct iphdr *iph; struct pktgen_hdr *pgh = NULL; skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC); if (!skb) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -