1/* -*-linux-c-*- 2 * $Id: pktgen.c,v 1.1.1.1 2008/10/15 03:27:33 james26_jang Exp $ 3 * pktgen.c: Packet Generator for performance evaluation. 4 * 5 * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> 6 * Uppsala University, Sweden 7 * 8 * A tool for loading the network with preconfigurated packets. 9 * The tool is implemented as a linux module. Parameters are output 10 * device, IPG (interpacket gap), number of packets, and whether 11 * to use multiple SKBs or just the same one. 12 * pktgen uses the installed interface's output routine. 13 * 14 * Additional hacking by: 15 * 16 * Jens.Laas@data.slu.se 17 * Improved by ANK. 010120. 18 * Improved by ANK even more. 010212. 19 * MAC address typo fixed. 010417 --ro 20 * Integrated. 020301 --DaveM 21 * Added multiskb option 020301 --DaveM 22 * Scaling of results. 020417--sigurdur@linpro.no 23 * Significant re-work of the module: 24 * * Updated to support generation over multiple interfaces at once 25 * by creating 32 /proc/net/pg* files. Each file can be manipulated 26 * individually. 27 * * Converted many counters to __u64 to allow longer runs. 28 * * Allow configuration of ranges, like min/max IP address, MACs, 29 * and UDP-ports, for both source and destination, and can 30 * set to use a random distribution or sequentially walk the range. 31 * * Can now change some values after starting. 32 * * Place 12-byte packet in UDP payload with magic number, 33 * sequence number, and timestamp. Will write receiver next. 34 * * The new changes seem to have a performance impact of around 1%, 35 * as far as I can tell. 36 * --Ben Greear <greearb@candelatech.com> 37 * 38 * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 39 * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 40 * as a "fastpath" with a configurable number of clones after alloc's. 41 * 42 * clone_skb=0 means all packets are allocated this also means ranges time 43 * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 44 * clones. 45 * 46 * Also moved to /proc/net/pktgen/ 47 * --ro 48 * 49 * See Documentation/networking/pktgen.txt for how to use this. 50 */ 51 52#include <linux/module.h> 53#include <linux/kernel.h> 54#include <linux/sched.h> 55#include <linux/types.h> 56#include <linux/string.h> 57#include <linux/ptrace.h> 58#include <linux/errno.h> 59#include <linux/ioport.h> 60#include <linux/slab.h> 61#include <linux/interrupt.h> 62#include <linux/pci.h> 63#include <linux/delay.h> 64#include <linux/init.h> 65#include <linux/inet.h> 66#include <asm/byteorder.h> 67#include <asm/bitops.h> 68#include <asm/io.h> 69#include <asm/dma.h> 70#include <asm/uaccess.h> 71 72#include <linux/in.h> 73#include <linux/ip.h> 74#include <linux/udp.h> 75#include <linux/skbuff.h> 76#include <linux/netdevice.h> 77#include <linux/inetdevice.h> 78#include <linux/rtnetlink.h> 79#include <linux/proc_fs.h> 80#include <linux/if_arp.h> 81#include <net/checksum.h> 82#include <asm/timex.h> 83 84#define cycles() ((u32)get_cycles()) 85 86 87#define VERSION "pktgen version 1.2" 88static char version[] __initdata = 89 "pktgen.c: v1.2: Packet Generator for packet performance testing.\n"; 90 91/* Used to help with determining the pkts on receive */ 92 93#define PKTGEN_MAGIC 0xbe9be955 94 95 96/* Keep information per interface */ 97struct pktgen_info { 98 /* Parameters */ 99 100 /* If min != max, then we will either do a linear iteration, or 101 * we will do a random selection from within the range. 102 */ 103 __u32 flags; 104 105#define F_IPSRC_RND (1<<0) /* IP-Src Random */ 106#define F_IPDST_RND (1<<1) /* IP-Dst Random */ 107#define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ 108#define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ 109#define F_MACSRC_RND (1<<4) /* MAC-Src Random */ 110#define F_MACDST_RND (1<<5) /* MAC-Dst Random */ 111#define F_SET_SRCMAC (1<<6) /* Specify-Src-Mac 112 (default is to use Interface's MAC Addr) */ 113#define F_SET_SRCIP (1<<7) /* Specify-Src-IP 114 (default is to use Interface's IP Addr) */ 115 116 117 int pkt_size; /* = ETH_ZLEN; */ 118 int nfrags; 119 __u32 ipg; /* Default Interpacket gap in nsec */ 120 __u64 count; /* Default No packets to send */ 121 __u64 sofar; /* How many pkts we've sent so far */ 122 __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ 123 struct timeval started_at; 124 struct timeval stopped_at; 125 __u64 idle_acc; 126 __u32 seq_num; 127 128 int clone_skb; /* Use multiple SKBs during packet gen. If this number 129 * is greater than 1, then that many coppies of the same 130 * packet will be sent before a new packet is allocated. 131 * For instance, if you want to send 1024 identical packets 132 * before creating a new packet, set clone_skb to 1024. 133 */ 134 int busy; 135 int do_run_run; /* if this changes to false, the test will stop */ 136 137 char outdev[32]; 138 char dst_min[32]; 139 char dst_max[32]; 140 char src_min[32]; 141 char src_max[32]; 142 143 /* If we're doing ranges, random or incremental, then this 144 * defines the min/max for those ranges. 145 */ 146 __u32 saddr_min; /* inclusive, source IP address */ 147 __u32 saddr_max; /* exclusive, source IP address */ 148 __u32 daddr_min; /* inclusive, dest IP address */ 149 __u32 daddr_max; /* exclusive, dest IP address */ 150 151 __u16 udp_src_min; /* inclusive, source UDP port */ 152 __u16 udp_src_max; /* exclusive, source UDP port */ 153 __u16 udp_dst_min; /* inclusive, dest UDP port */ 154 __u16 udp_dst_max; /* exclusive, dest UDP port */ 155 156 __u32 src_mac_count; /* How many MACs to iterate through */ 157 __u32 dst_mac_count; /* How many MACs to iterate through */ 158 159 unsigned char dst_mac[6]; 160 unsigned char src_mac[6]; 161 162 __u32 cur_dst_mac_offset; 163 __u32 cur_src_mac_offset; 164 __u32 cur_saddr; 165 __u32 cur_daddr; 166 __u16 cur_udp_dst; 167 __u16 cur_udp_src; 168 169 __u8 hh[14]; 170 /* = { 171 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 172 173 We fill in SRC address later 174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 0x08, 0x00 176 }; 177 */ 178 __u16 pad; /* pad out the hh struct to an even 16 bytes */ 179 char result[512]; 180 181 /* proc file names */ 182 char fname[80]; 183 char busy_fname[80]; 184 185 struct proc_dir_entry *proc_ent; 186 struct proc_dir_entry *busy_proc_ent; 187}; 188 189struct pktgen_hdr { 190 __u32 pgh_magic; 191 __u32 seq_num; 192 struct timeval timestamp; 193}; 194 195static int cpu_speed; 196static int debug; 197 198/* Module parameters, defaults. */ 199static int count_d = 100000; 200static int ipg_d = 0; 201static int clone_skb_d = 0; 202 203 204#define MAX_PKTGEN 8 205static struct pktgen_info pginfos[MAX_PKTGEN]; 206 207 208/** Convert to miliseconds */ 209inline __u64 tv_to_ms(const struct timeval* tv) { 210 __u64 ms = tv->tv_usec / 1000; 211 ms += (__u64)tv->tv_sec * (__u64)1000; 212 return ms; 213} 214 215inline __u64 getCurMs(void) { 216 struct timeval tv; 217 do_gettimeofday(&tv); 218 return tv_to_ms(&tv); 219} 220 221#define PG_PROC_DIR "pktgen" 222static struct proc_dir_entry *proc_dir = 0; 223 224static struct net_device *setup_inject(struct pktgen_info* info) 225{ 226 struct net_device *odev; 227 228 rtnl_lock(); 229 odev = __dev_get_by_name(info->outdev); 230 if (!odev) { 231 sprintf(info->result, "No such netdevice: \"%s\"", info->outdev); 232 goto out_unlock; 233 } 234 235 if (odev->type != ARPHRD_ETHER) { 236 sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev); 237 goto out_unlock; 238 } 239 240 if (!netif_running(odev)) { 241 sprintf(info->result, "Device is down: \"%s\"", info->outdev); 242 goto out_unlock; 243 } 244 245 /* Default to the interface's mac if not explicitly set. */ 246 if (!(info->flags & F_SET_SRCMAC)) { 247 memcpy(&(info->hh[6]), odev->dev_addr, 6); 248 } 249 else { 250 memcpy(&(info->hh[6]), info->src_mac, 6); 251 } 252 253 /* Set up Dest MAC */ 254 memcpy(&(info->hh[0]), info->dst_mac, 6); 255 256 info->saddr_min = 0; 257 info->saddr_max = 0; 258 if (strlen(info->src_min) == 0) { 259 if (odev->ip_ptr) { 260 struct in_device *in_dev = odev->ip_ptr; 261 262 if (in_dev->ifa_list) { 263 info->saddr_min = in_dev->ifa_list->ifa_address; 264 info->saddr_max = info->saddr_min; 265 } 266 } 267 } 268 else { 269 info->saddr_min = in_aton(info->src_min); 270 info->saddr_max = in_aton(info->src_max); 271 } 272 273 info->daddr_min = in_aton(info->dst_min); 274 info->daddr_max = in_aton(info->dst_max); 275 276 /* Initialize current values. */ 277 info->cur_dst_mac_offset = 0; 278 info->cur_src_mac_offset = 0; 279 info->cur_saddr = info->saddr_min; 280 info->cur_daddr = info->daddr_min; 281 info->cur_udp_dst = info->udp_dst_min; 282 info->cur_udp_src = info->udp_src_min; 283 284 atomic_inc(&odev->refcnt); 285 rtnl_unlock(); 286 287 return odev; 288 289out_unlock: 290 rtnl_unlock(); 291 return NULL; 292} 293 294static void nanospin(int ipg, struct pktgen_info* info) 295{ 296 u32 idle_start, idle; 297 298 idle_start = cycles(); 299 300 for (;;) { 301 barrier(); 302 idle = cycles() - idle_start; 303 if (idle * 1000 >= ipg * cpu_speed) 304 break; 305 } 306 info->idle_acc += idle; 307} 308 309static int calc_mhz(void) 310{ 311 struct timeval start, stop; 312 u32 start_s, elapsed; 313 314 do_gettimeofday(&start); 315 start_s = cycles(); 316 do { 317 barrier(); 318 elapsed = cycles() - start_s; 319 if (elapsed == 0) 320 return 0; 321 } while (elapsed < 1000 * 50000); 322 do_gettimeofday(&stop); 323 return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec)); 324} 325 326static void cycles_calibrate(void) 327{ 328 int i; 329 330 for (i = 0; i < 3; i++) { 331 int res = calc_mhz(); 332 if (res > cpu_speed) 333 cpu_speed = res; 334 } 335} 336 337 338/* Increment/randomize headers according to flags and current values 339 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 340 */ 341static void mod_cur_headers(struct pktgen_info* info) { 342 __u32 imn; 343 __u32 imx; 344 345 /* Deal with source MAC */ 346 if (info->src_mac_count > 1) { 347 __u32 mc; 348 __u32 tmp; 349 if (info->flags & F_MACSRC_RND) { 350 mc = net_random() % (info->src_mac_count); 351 } 352 else { 353 mc = info->cur_src_mac_offset++; 354 if (info->cur_src_mac_offset > info->src_mac_count) { 355 info->cur_src_mac_offset = 0; 356 } 357 } 358 359 tmp = info->src_mac[5] + (mc & 0xFF); 360 info->hh[11] = tmp; 361 tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 362 info->hh[10] = tmp; 363 tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 364 info->hh[9] = tmp; 365 tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 366 info->hh[8] = tmp; 367 tmp = (info->src_mac[1] + (tmp >> 8)); 368 info->hh[7] = tmp; 369 } 370 371 /* Deal with Destination MAC */ 372 if (info->dst_mac_count > 1) { 373 __u32 mc; 374 __u32 tmp; 375 if (info->flags & F_MACDST_RND) { 376 mc = net_random() % (info->dst_mac_count); 377 } 378 else { 379 mc = info->cur_dst_mac_offset++; 380 if (info->cur_dst_mac_offset > info->dst_mac_count) { 381 info->cur_dst_mac_offset = 0; 382 } 383 } 384 385 tmp = info->dst_mac[5] + (mc & 0xFF); 386 info->hh[5] = tmp; 387 tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 388 info->hh[4] = tmp; 389 tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 390 info->hh[3] = tmp; 391 tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 392 info->hh[2] = tmp; 393 tmp = (info->dst_mac[1] + (tmp >> 8)); 394 info->hh[1] = tmp; 395 } 396 397 if (info->udp_src_min < info->udp_src_max) { 398 if (info->flags & F_UDPSRC_RND) { 399 info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min)) 400 + info->udp_src_min); 401 } 402 else { 403 info->cur_udp_src++; 404 if (info->cur_udp_src >= info->udp_src_max) { 405 info->cur_udp_src = info->udp_src_min; 406 } 407 } 408 } 409 410 if (info->udp_dst_min < info->udp_dst_max) { 411 if (info->flags & F_UDPDST_RND) { 412 info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min)) 413 + info->udp_dst_min); 414 } 415 else { 416 info->cur_udp_dst++; 417 if (info->cur_udp_dst >= info->udp_dst_max) { 418 info->cur_udp_dst = info->udp_dst_min; 419 } 420 } 421 } 422 423 if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) { 424 __u32 t; 425 if (info->flags & F_IPSRC_RND) { 426 t = ((net_random() % (imx - imn)) + imn); 427 } 428 else { 429 t = ntohl(info->cur_saddr); 430 t++; 431 if (t >= imx) { 432 t = imn; 433 } 434 } 435 info->cur_saddr = htonl(t); 436 } 437 438 if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) { 439 __u32 t; 440 if (info->flags & F_IPDST_RND) { 441 t = ((net_random() % (imx - imn)) + imn); 442 } 443 else { 444 t = ntohl(info->cur_daddr); 445 t++; 446 if (t >= imx) { 447 t = imn; 448 } 449 } 450 info->cur_daddr = htonl(t); 451 } 452}/* mod_cur_headers */ 453 454 455static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info) 456{ 457 struct sk_buff *skb = NULL; 458 __u8 *eth; 459 struct udphdr *udph; 460 int datalen, iplen; 461 struct iphdr *iph; 462 struct pktgen_hdr *pgh = NULL; 463 464 skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC); 465 if (!skb) { 466 sprintf(info->result, "No memory"); 467 return NULL; 468 } 469 470 skb_reserve(skb, 16); 471 472 /* Reserve for ethernet and IP header */ 473 eth = (__u8 *) skb_push(skb, 14); 474 iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); 475 udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); 476 477 /* Update any of the values, used when we're incrementing various 478 * fields. 479 */ 480 mod_cur_headers(info); 481 482 memcpy(eth, info->hh, 14); 483 484 datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ 485 if (datalen < sizeof(struct pktgen_hdr)) { 486 datalen = sizeof(struct pktgen_hdr); 487 } 488 489 udph->source = htons(info->cur_udp_src); 490 udph->dest = htons(info->cur_udp_dst); 491 udph->len = htons(datalen + 8); /* DATA + udphdr */ 492 udph->check = 0; /* No checksum */ 493 494 iph->ihl = 5; 495 iph->version = 4; 496 iph->ttl = 3; 497 iph->tos = 0; 498 iph->protocol = IPPROTO_UDP; /* UDP */ 499 iph->saddr = info->cur_saddr; 500 iph->daddr = info->cur_daddr; 501 iph->frag_off = 0; 502 iplen = 20 + 8 + datalen; 503 iph->tot_len = htons(iplen); 504 iph->check = 0; 505 iph->check = ip_fast_csum((void *) iph, iph->ihl); 506 skb->protocol = __constant_htons(ETH_P_IP); 507 skb->mac.raw = ((u8 *)iph) - 14; 508 skb->dev = odev; 509 skb->pkt_type = PACKET_HOST; 510 511 if (info->nfrags <= 0) { 512 pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 513 } else { 514 int frags = info->nfrags; 515 int i; 516 517 /* TODO: Verify this is OK...it sure is ugly. --Ben */ 518 pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); 519 520 if (frags > MAX_SKB_FRAGS) 521 frags = MAX_SKB_FRAGS; 522 if (datalen > frags*PAGE_SIZE) { 523 skb_put(skb, datalen-frags*PAGE_SIZE); 524 datalen = frags*PAGE_SIZE; 525 } 526 527 i = 0; 528 while (datalen > 0) { 529 struct page *page = alloc_pages(GFP_KERNEL, 0); 530 skb_shinfo(skb)->frags[i].page = page; 531 skb_shinfo(skb)->frags[i].page_offset = 0; 532 skb_shinfo(skb)->frags[i].size = 533 (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 534 datalen -= skb_shinfo(skb)->frags[i].size; 535 skb->len += skb_shinfo(skb)->frags[i].size; 536 skb->data_len += skb_shinfo(skb)->frags[i].size; 537 i++; 538 skb_shinfo(skb)->nr_frags = i; 539 } 540 541 while (i < frags) { 542 int rem; 543 544 if (i == 0) 545 break; 546 547 rem = skb_shinfo(skb)->frags[i - 1].size / 2; 548 if (rem == 0) 549 break; 550 551 skb_shinfo(skb)->frags[i - 1].size -= rem; 552 553 skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1]; 554 get_page(skb_shinfo(skb)->frags[i].page); 555 skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page; 556 skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size; 557 skb_shinfo(skb)->frags[i].size = rem; 558 i++; 559 skb_shinfo(skb)->nr_frags = i; 560 } 561 } 562 563 /* Stamp the time, and sequence number, convert them to network byte order */ 564 if (pgh) { 565 pgh->pgh_magic = htonl(PKTGEN_MAGIC); 566 do_gettimeofday(&(pgh->timestamp)); 567 pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec); 568 pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec); 569 pgh->seq_num = htonl(info->seq_num); 570 } 571 572 return skb; 573} 574 575 576static void inject(struct pktgen_info* info) 577{ 578 struct net_device *odev = NULL; 579 struct sk_buff *skb = NULL; 580 __u64 total = 0; 581 __u64 idle = 0; 582 __u64 lcount = 0; 583 int nr_frags = 0; 584 int last_ok = 1; /* Was last skb sent? 585 * Or a failed transmit of some sort? This will keep 586 * sequence numbers in order, for example. 587 */ 588 __u64 fp = 0; 589 __u32 fp_tmp = 0; 590 591 odev = setup_inject(info); 592 if (!odev) 593 return; 594 595 info->do_run_run = 1; /* Cranke yeself! */ 596 info->idle_acc = 0; 597 info->sofar = 0; 598 lcount = info->count; 599 600 601 /* Build our initial pkt and place it as a re-try pkt. */ 602 skb = fill_packet(odev, info); 603 if (skb == NULL) goto out_reldev; 604 605 do_gettimeofday(&(info->started_at)); 606 607 while(info->do_run_run) { 608 609 /* Set a time-stamp, so build a new pkt each time */ 610 611 if (last_ok) { 612 if (++fp_tmp >= info->clone_skb ) { 613 kfree_skb(skb); 614 skb = fill_packet(odev, info); 615 if (skb == NULL) { 616 break; 617 } 618 fp++; 619 fp_tmp = 0; /* reset counter */ 620 } 621 atomic_inc(&skb->users); 622 } 623 624 nr_frags = skb_shinfo(skb)->nr_frags; 625 626 spin_lock_bh(&odev->xmit_lock); 627 if (!netif_queue_stopped(odev)) { 628 629 if (odev->hard_start_xmit(skb, odev)) { 630 if (net_ratelimit()) { 631 printk(KERN_INFO "Hard xmit error\n"); 632 } 633 info->errors++; 634 last_ok = 0; 635 } 636 else { 637 last_ok = 1; 638 info->sofar++; 639 info->seq_num++; 640 } 641 } 642 else { 643 /* Re-try it next time */ 644 last_ok = 0; 645 } 646 647 648 spin_unlock_bh(&odev->xmit_lock); 649 650 if (info->ipg) { 651 /* Try not to busy-spin if we have larger sleep times. 652 * TODO: Investigate better ways to do this. 653 */ 654 if (info->ipg < 10000) { /* 10 usecs or less */ 655 nanospin(info->ipg, info); 656 } 657 else if (info->ipg < 10000000) { /* 10ms or less */ 658 udelay(info->ipg / 1000); 659 } 660 else { 661 mdelay(info->ipg / 1000000); 662 } 663 } 664 665 if (signal_pending(current)) { 666 break; 667 } 668 669 /* If lcount is zero, then run forever */ 670 if ((lcount != 0) && (--lcount == 0)) { 671 if (atomic_read(&skb->users) != 1) { 672 u32 idle_start, idle; 673 674 idle_start = cycles(); 675 while (atomic_read(&skb->users) != 1) { 676 if (signal_pending(current)) { 677 break; 678 } 679 schedule(); 680 } 681 idle = cycles() - idle_start; 682 info->idle_acc += idle; 683 } 684 break; 685 } 686 687 if (netif_queue_stopped(odev) || current->need_resched) { 688 u32 idle_start, idle; 689 690 idle_start = cycles(); 691 do { 692 if (signal_pending(current)) { 693 info->do_run_run = 0; 694 break; 695 } 696 if (!netif_running(odev)) { 697 info->do_run_run = 0; 698 break; 699 } 700 if (current->need_resched) 701 schedule(); 702 else 703 do_softirq(); 704 } while (netif_queue_stopped(odev)); 705 idle = cycles() - idle_start; 706 info->idle_acc += idle; 707 } 708 }/* while we should be running */ 709 710 do_gettimeofday(&(info->stopped_at)); 711 712 total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 + 713 info->stopped_at.tv_usec - info->started_at.tv_usec; 714 715 idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed); 716 717 { 718 char *p = info->result; 719 __u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000); 720 __u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */ 721 p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps) errors: %llu", 722 (unsigned long long) total, 723 (unsigned long long) (total - idle), 724 (unsigned long long) idle, 725 (unsigned long long) info->sofar, 726 skb->len + 4, /* Add 4 to account for the ethernet checksum */ 727 nr_frags, 728 (unsigned long long) pps, 729 (unsigned long long) (bps / (u64) 1024 / (u64) 1024), 730 (unsigned long long) bps, 731 (unsigned long long) info->errors 732 ); 733 } 734 735out_reldev: 736 if (odev) { 737 dev_put(odev); 738 odev = NULL; 739 } 740 741 /* TODO: Is this worth printing out (other than for debug?) */ 742 printk("fp = %llu\n", (unsigned long long) fp); 743 return; 744 745} 746 747/* proc/net/pktgen/pg */ 748 749static int proc_busy_read(char *buf , char **start, off_t offset, 750 int len, int *eof, void *data) 751{ 752 char *p; 753 int idx = (int)(long)(data); 754 struct pktgen_info* info = NULL; 755 756 if ((idx < 0) || (idx >= MAX_PKTGEN)) { 757 printk("ERROR: idx: %i is out of range in proc_write\n", idx); 758 return -EINVAL; 759 } 760 info = &(pginfos[idx]); 761 762 p = buf; 763 p += sprintf(p, "%d\n", info->busy); 764 *eof = 1; 765 766 return p-buf; 767} 768 769static int proc_read(char *buf , char **start, off_t offset, 770 int len, int *eof, void *data) 771{ 772 char *p; 773 int i; 774 int idx = (int)(long)(data); 775 struct pktgen_info* info = NULL; 776 __u64 sa; 777 __u64 stopped; 778 __u64 now = getCurMs(); 779 780 if ((idx < 0) || (idx >= MAX_PKTGEN)) { 781 printk("ERROR: idx: %i is out of range in proc_write\n", idx); 782 return -EINVAL; 783 } 784 info = &(pginfos[idx]); 785 786 p = buf; 787 p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */ 788 p += sprintf(p, "Params: count %llu pkt_size: %u frags: %d ipg: %u clone_skb: %d odev \"%s\"\n", 789 (unsigned long long) info->count, 790 info->pkt_size, info->nfrags, info->ipg, 791 info->clone_skb, info->outdev); 792 p += sprintf(p, " dst_min: %s dst_max: %s src_min: %s src_max: %s\n", 793 info->dst_min, info->dst_max, info->src_min, info->src_max); 794 p += sprintf(p, " src_mac: "); 795 for (i = 0; i < 6; i++) { 796 p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? " " : ":"); 797 } 798 p += sprintf(p, "dst_mac: "); 799 for (i = 0; i < 6; i++) { 800 p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":"); 801 } 802 p += sprintf(p, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", 803 info->udp_src_min, info->udp_src_max, info->udp_dst_min, 804 info->udp_dst_max); 805 p += sprintf(p, " src_mac_count: %d dst_mac_count: %d\n Flags: ", 806 info->src_mac_count, info->dst_mac_count); 807 if (info->flags & F_IPSRC_RND) { 808 p += sprintf(p, "IPSRC_RND "); 809 } 810 if (info->flags & F_IPDST_RND) { 811 p += sprintf(p, "IPDST_RND "); 812 } 813 if (info->flags & F_UDPSRC_RND) { 814 p += sprintf(p, "UDPSRC_RND "); 815 } 816 if (info->flags & F_UDPDST_RND) { 817 p += sprintf(p, "UDPDST_RND "); 818 } 819 if (info->flags & F_MACSRC_RND) { 820 p += sprintf(p, "MACSRC_RND "); 821 } 822 if (info->flags & F_MACDST_RND) { 823 p += sprintf(p, "MACDST_RND "); 824 } 825 p += sprintf(p, "\n"); 826 827 sa = tv_to_ms(&(info->started_at)); 828 stopped = tv_to_ms(&(info->stopped_at)); 829 if (info->do_run_run) { 830 stopped = now; /* not really stopped, more like last-running-at */ 831 } 832 p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %llums stopped: %llums now: %llums idle: %lluns\n", 833 (unsigned long long) info->sofar, 834 (unsigned long long) info->errors, 835 (unsigned long long) sa, 836 (unsigned long long) stopped, 837 (unsigned long long) now, 838 (unsigned long long) info->idle_acc); 839 p += sprintf(p, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 840 info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset); 841 p += sprintf(p, " cur_saddr: 0x%x cur_daddr: 0x%x cur_udp_dst: %d cur_udp_src: %d\n", 842 info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src); 843 844 if (info->result[0]) 845 p += sprintf(p, "Result: %s\n", info->result); 846 else 847 p += sprintf(p, "Result: Idle\n"); 848 *eof = 1; 849 850 return p - buf; 851} 852 853static int count_trail_chars(const char *user_buffer, unsigned int maxlen) 854{ 855 int i; 856 857 for (i = 0; i < maxlen; i++) { 858 char c; 859 860 if (get_user(c, &user_buffer[i])) 861 return -EFAULT; 862 switch (c) { 863 case '\"': 864 case '\n': 865 case '\r': 866 case '\t': 867 case ' ': 868 case '=': 869 break; 870 default: 871 goto done; 872 }; 873 } 874done: 875 return i; 876} 877 878static unsigned long num_arg(const char *user_buffer, unsigned long maxlen, 879 unsigned long *num) 880{ 881 int i = 0; 882 883 *num = 0; 884 885 for(; i < maxlen; i++) { 886 char c; 887 888 if (get_user(c, &user_buffer[i])) 889 return -EFAULT; 890 if ((c >= '0') && (c <= '9')) { 891 *num *= 10; 892 *num += c -'0'; 893 } else 894 break; 895 } 896 return i; 897} 898 899static int strn_len(const char *user_buffer, unsigned int maxlen) 900{ 901 int i = 0; 902 903 for(; i < maxlen; i++) { 904 char c; 905 906 if (get_user(c, &user_buffer[i])) 907 return -EFAULT; 908 switch (c) { 909 case '\"': 910 case '\n': 911 case '\r': 912 case '\t': 913 case ' ': 914 goto done_str; 915 default: 916 break; 917 }; 918 } 919done_str: 920 return i; 921} 922 923static int proc_write(struct file *file, const char *user_buffer, 924 unsigned long count, void *data) 925{ 926 int i = 0, max, len; 927 char name[16], valstr[32]; 928 unsigned long value = 0; 929 int idx = (int)(long)(data); 930 struct pktgen_info* info = NULL; 931 char* result = NULL; 932 int tmp; 933 934 if ((idx < 0) || (idx >= MAX_PKTGEN)) { 935 printk("ERROR: idx: %i is out of range in proc_write\n", idx); 936 return -EINVAL; 937 } 938 info = &(pginfos[idx]); 939 result = &(info->result[0]); 940 941 if (count < 1) { 942 sprintf(result, "Wrong command format"); 943 return -EINVAL; 944 } 945 946 max = count - i; 947 tmp = count_trail_chars(&user_buffer[i], max); 948 if (tmp < 0) 949 return tmp; 950 i += tmp; 951 952 /* Read variable name */ 953 954 len = strn_len(&user_buffer[i], sizeof(name) - 1); 955 if (len < 0) 956 return len; 957 memset(name, 0, sizeof(name)); 958 copy_from_user(name, &user_buffer[i], len); 959 i += len; 960 961 max = count -i; 962 len = count_trail_chars(&user_buffer[i], max); 963 if (len < 0) 964 return len; 965 i += len; 966 967 if (debug) 968 printk("pg: %s,%lu\n", name, count); 969 970 if (!strcmp(name, "stop")) { 971 if (info->do_run_run) { 972 strcpy(result, "Stopping"); 973 } 974 else { 975 strcpy(result, "Already stopped...\n"); 976 } 977 info->do_run_run = 0; 978 return count; 979 } 980 981 if (!strcmp(name, "pkt_size")) { 982 len = num_arg(&user_buffer[i], 10, &value); 983 if (len < 0) 984 return len; 985 i += len; 986 if (value < 14+20+8) 987 value = 14+20+8; 988 info->pkt_size = value; 989 sprintf(result, "OK: pkt_size=%u", info->pkt_size); 990 return count; 991 } 992 if (!strcmp(name, "frags")) { 993 len = num_arg(&user_buffer[i], 10, &value); 994 if (len < 0) 995 return len; 996 i += len; 997 info->nfrags = value; 998 sprintf(result, "OK: frags=%u", info->nfrags); 999 return count; 1000 } 1001 if (!strcmp(name, "ipg")) { 1002 len = num_arg(&user_buffer[i], 10, &value); 1003 if (len < 0) 1004 return len; 1005 i += len; 1006 info->ipg = value; 1007 sprintf(result, "OK: ipg=%u", info->ipg); 1008 return count; 1009 } 1010 if (!strcmp(name, "udp_src_min")) { 1011 len = num_arg(&user_buffer[i], 10, &value); 1012 if (len < 0) 1013 return len; 1014 i += len; 1015 info->udp_src_min = value; 1016 sprintf(result, "OK: udp_src_min=%u", info->udp_src_min); 1017 return count; 1018 } 1019 if (!strcmp(name, "udp_dst_min")) { 1020 len = num_arg(&user_buffer[i], 10, &value); 1021 if (len < 0) 1022 return len; 1023 i += len; 1024 info->udp_dst_min = value; 1025 sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min); 1026 return count; 1027 } 1028 if (!strcmp(name, "udp_src_max")) { 1029 len = num_arg(&user_buffer[i], 10, &value); 1030 if (len < 0) 1031 return len; 1032 i += len; 1033 info->udp_src_max = value; 1034 sprintf(result, "OK: udp_src_max=%u", info->udp_src_max); 1035 return count; 1036 } 1037 if (!strcmp(name, "udp_dst_max")) { 1038 len = num_arg(&user_buffer[i], 10, &value); 1039 if (len < 0) 1040 return len; 1041 i += len; 1042 info->udp_dst_max = value; 1043 sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max); 1044 return count; 1045 } 1046 if (!strcmp(name, "clone_skb")) { 1047 len = num_arg(&user_buffer[i], 10, &value); 1048 if (len < 0) 1049 return len; 1050 i += len; 1051 info->clone_skb = value; 1052 1053 sprintf(result, "OK: clone_skb=%d", info->clone_skb); 1054 return count; 1055 } 1056 if (!strcmp(name, "count")) { 1057 len = num_arg(&user_buffer[i], 10, &value); 1058 if (len < 0) 1059 return len; 1060 i += len; 1061 info->count = value; 1062 sprintf(result, "OK: count=%llu", (unsigned long long) info->count); 1063 return count; 1064 } 1065 if (!strcmp(name, "src_mac_count")) { 1066 len = num_arg(&user_buffer[i], 10, &value); 1067 if (len < 0) 1068 return len; 1069 i += len; 1070 info->src_mac_count = value; 1071 sprintf(result, "OK: src_mac_count=%d", info->src_mac_count); 1072 return count; 1073 } 1074 if (!strcmp(name, "dst_mac_count")) { 1075 len = num_arg(&user_buffer[i], 10, &value); 1076 if (len < 0) 1077 return len; 1078 i += len; 1079 info->dst_mac_count = value; 1080 sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count); 1081 return count; 1082 } 1083 if (!strcmp(name, "odev")) { 1084 len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1); 1085 if (len < 0) 1086 return len; 1087 memset(info->outdev, 0, sizeof(info->outdev)); 1088 copy_from_user(info->outdev, &user_buffer[i], len); 1089 i += len; 1090 sprintf(result, "OK: odev=%s", info->outdev); 1091 return count; 1092 } 1093 if (!strcmp(name, "flag")) { 1094 char f[32]; 1095 memset(f, 0, 32); 1096 len = strn_len(&user_buffer[i], sizeof(f) - 1); 1097 if (len < 0) 1098 return len; 1099 copy_from_user(f, &user_buffer[i], len); 1100 i += len; 1101 if (strcmp(f, "IPSRC_RND") == 0) { 1102 info->flags |= F_IPSRC_RND; 1103 } 1104 else if (strcmp(f, "!IPSRC_RND") == 0) { 1105 info->flags &= ~F_IPSRC_RND; 1106 } 1107 else if (strcmp(f, "IPDST_RND") == 0) { 1108 info->flags |= F_IPDST_RND; 1109 } 1110 else if (strcmp(f, "!IPDST_RND") == 0) { 1111 info->flags &= ~F_IPDST_RND; 1112 } 1113 else if (strcmp(f, "UDPSRC_RND") == 0) { 1114 info->flags |= F_UDPSRC_RND; 1115 } 1116 else if (strcmp(f, "!UDPSRC_RND") == 0) { 1117 info->flags &= ~F_UDPSRC_RND; 1118 } 1119 else if (strcmp(f, "UDPDST_RND") == 0) { 1120 info->flags |= F_UDPDST_RND; 1121 } 1122 else if (strcmp(f, "!UDPDST_RND") == 0) { 1123 info->flags &= ~F_UDPDST_RND; 1124 } 1125 else if (strcmp(f, "MACSRC_RND") == 0) { 1126 info->flags |= F_MACSRC_RND; 1127 } 1128 else if (strcmp(f, "!MACSRC_RND") == 0) { 1129 info->flags &= ~F_MACSRC_RND; 1130 } 1131 else if (strcmp(f, "MACDST_RND") == 0) { 1132 info->flags |= F_MACDST_RND; 1133 } 1134 else if (strcmp(f, "!MACDST_RND") == 0) { 1135 info->flags &= ~F_MACDST_RND; 1136 } 1137 else { 1138 sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 1139 f, 1140 "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); 1141 return count; 1142 } 1143 sprintf(result, "OK: flags=0x%x", info->flags); 1144 return count; 1145 } 1146 if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 1147 len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1); 1148 if (len < 0) 1149 return len; 1150 memset(info->dst_min, 0, sizeof(info->dst_min)); 1151 copy_from_user(info->dst_min, &user_buffer[i], len); 1152 if(debug) 1153 printk("pg: dst_min set to: %s\n", info->dst_min); 1154 i += len; 1155 sprintf(result, "OK: dst_min=%s", info->dst_min); 1156 return count; 1157 } 1158 if (!strcmp(name, "dst_max")) { 1159 len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1); 1160 if (len < 0) 1161 return len; 1162 memset(info->dst_max, 0, sizeof(info->dst_max)); 1163 copy_from_user(info->dst_max, &user_buffer[i], len); 1164 if(debug) 1165 printk("pg: dst_max set to: %s\n", info->dst_max); 1166 i += len; 1167 sprintf(result, "OK: dst_max=%s", info->dst_max); 1168 return count; 1169 } 1170 if (!strcmp(name, "src_min")) { 1171 len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1); 1172 if (len < 0) 1173 return len; 1174 memset(info->src_min, 0, sizeof(info->src_min)); 1175 copy_from_user(info->src_min, &user_buffer[i], len); 1176 if(debug) 1177 printk("pg: src_min set to: %s\n", info->src_min); 1178 i += len; 1179 sprintf(result, "OK: src_min=%s", info->src_min); 1180 return count; 1181 } 1182 if (!strcmp(name, "src_max")) { 1183 len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1); 1184 if (len < 0) 1185 return len; 1186 memset(info->src_max, 0, sizeof(info->src_max)); 1187 copy_from_user(info->src_max, &user_buffer[i], len); 1188 if(debug) 1189 printk("pg: src_max set to: %s\n", info->src_max); 1190 i += len; 1191 sprintf(result, "OK: src_max=%s", info->src_max); 1192 return count; 1193 } 1194 if (!strcmp(name, "dstmac")) { 1195 char *v = valstr; 1196 unsigned char *m = info->dst_mac; 1197 1198 len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 1199 if (len < 0) 1200 return len; 1201 memset(valstr, 0, sizeof(valstr)); 1202 copy_from_user(valstr, &user_buffer[i], len); 1203 i += len; 1204 1205 for(*m = 0;*v && m < info->dst_mac + 6; v++) { 1206 if (*v >= '0' && *v <= '9') { 1207 *m *= 16; 1208 *m += *v - '0'; 1209 } 1210 if (*v >= 'A' && *v <= 'F') { 1211 *m *= 16; 1212 *m += *v - 'A' + 10; 1213 } 1214 if (*v >= 'a' && *v <= 'f') { 1215 *m *= 16; 1216 *m += *v - 'a' + 10; 1217 } 1218 if (*v == ':') { 1219 m++; 1220 *m = 0; 1221 } 1222 } 1223 sprintf(result, "OK: dstmac"); 1224 return count; 1225 } 1226 if (!strcmp(name, "srcmac")) { 1227 char *v = valstr; 1228 unsigned char *m = info->src_mac; 1229 1230 len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 1231 if (len < 0) 1232 return len; 1233 memset(valstr, 0, sizeof(valstr)); 1234 copy_from_user(valstr, &user_buffer[i], len); 1235 i += len; 1236 1237 for(*m = 0;*v && m < info->src_mac + 6; v++) { 1238 if (*v >= '0' && *v <= '9') { 1239 *m *= 16; 1240 *m += *v - '0'; 1241 } 1242 if (*v >= 'A' && *v <= 'F') { 1243 *m *= 16; 1244 *m += *v - 'A' + 10; 1245 } 1246 if (*v >= 'a' && *v <= 'f') { 1247 *m *= 16; 1248 *m += *v - 'a' + 10; 1249 } 1250 if (*v == ':') { 1251 m++; 1252 *m = 0; 1253 } 1254 } 1255 sprintf(result, "OK: srcmac"); 1256 return count; 1257 } 1258 1259 if (!strcmp(name, "inject") || !strcmp(name, "start")) { 1260 MOD_INC_USE_COUNT; 1261 if (info->busy) { 1262 strcpy(info->result, "Already running...\n"); 1263 } 1264 else { 1265 info->busy = 1; 1266 strcpy(info->result, "Starting"); 1267 inject(info); 1268 info->busy = 0; 1269 } 1270 MOD_DEC_USE_COUNT; 1271 return count; 1272 } 1273 1274 sprintf(info->result, "No such parameter \"%s\"", name); 1275 return -EINVAL; 1276} 1277 1278 1279int create_proc_dir(void) 1280{ 1281 int len; 1282 /* does proc_dir already exists */ 1283 len = strlen(PG_PROC_DIR); 1284 1285 for (proc_dir = proc_net->subdir; proc_dir; 1286 proc_dir=proc_dir->next) { 1287 if ((proc_dir->namelen == len) && 1288 (! memcmp(proc_dir->name, PG_PROC_DIR, len))) 1289 break; 1290 } 1291 if (!proc_dir) 1292 proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net); 1293 if (!proc_dir) return -ENODEV; 1294 return 1; 1295} 1296 1297int remove_proc_dir(void) 1298{ 1299 remove_proc_entry(PG_PROC_DIR, proc_net); 1300 return 1; 1301} 1302 1303static int __init init(void) 1304{ 1305 int i; 1306 printk(version); 1307 cycles_calibrate(); 1308 if (cpu_speed == 0) { 1309 printk("pktgen: Error: your machine does not have working cycle counter.\n"); 1310 return -EINVAL; 1311 } 1312 1313 create_proc_dir(); 1314 1315 for (i = 0; i<MAX_PKTGEN; i++) { 1316 memset(&(pginfos[i]), 0, sizeof(pginfos[i])); 1317 pginfos[i].pkt_size = ETH_ZLEN; 1318 pginfos[i].nfrags = 0; 1319 pginfos[i].clone_skb = clone_skb_d; 1320 pginfos[i].ipg = ipg_d; 1321 pginfos[i].count = count_d; 1322 pginfos[i].sofar = 0; 1323 pginfos[i].hh[12] = 0x08; /* fill in protocol. Rest is filled in later. */ 1324 pginfos[i].hh[13] = 0x00; 1325 pginfos[i].udp_src_min = 9; /* sink NULL */ 1326 pginfos[i].udp_src_max = 9; 1327 pginfos[i].udp_dst_min = 9; 1328 pginfos[i].udp_dst_max = 9; 1329 1330 sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i); 1331 pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0); 1332 if (!pginfos[i].proc_ent) { 1333 printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR); 1334 goto cleanup_mem; 1335 } 1336 pginfos[i].proc_ent->read_proc = proc_read; 1337 pginfos[i].proc_ent->write_proc = proc_write; 1338 pginfos[i].proc_ent->data = (void*)(long)(i); 1339 1340 sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i); 1341 pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0); 1342 if (!pginfos[i].busy_proc_ent) { 1343 printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR); 1344 goto cleanup_mem; 1345 } 1346 pginfos[i].busy_proc_ent->read_proc = proc_busy_read; 1347 pginfos[i].busy_proc_ent->data = (void*)(long)(i); 1348 } 1349 return 0; 1350 1351cleanup_mem: 1352 for (i = 0; i<MAX_PKTGEN; i++) { 1353 if (strlen(pginfos[i].fname)) { 1354 remove_proc_entry(pginfos[i].fname, NULL); 1355 } 1356 if (strlen(pginfos[i].busy_fname)) { 1357 remove_proc_entry(pginfos[i].busy_fname, NULL); 1358 } 1359 } 1360 return -ENOMEM; 1361} 1362 1363 1364static void __exit cleanup(void) 1365{ 1366 int i; 1367 for (i = 0; i<MAX_PKTGEN; i++) { 1368 if (strlen(pginfos[i].fname)) { 1369 remove_proc_entry(pginfos[i].fname, NULL); 1370 } 1371 if (strlen(pginfos[i].busy_fname)) { 1372 remove_proc_entry(pginfos[i].busy_fname, NULL); 1373 } 1374 } 1375 remove_proc_dir(); 1376} 1377 1378module_init(init); 1379module_exit(cleanup); 1380 1381MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se"); 1382MODULE_DESCRIPTION("Packet Generator tool"); 1383MODULE_LICENSE("GPL"); 1384MODULE_PARM(count_d, "i"); 1385MODULE_PARM(ipg_d, "i"); 1386MODULE_PARM(cpu_speed, "i"); 1387MODULE_PARM(clone_skb_d, "i"); 1388 1389 1390 1391