📄 pktgen.c
字号:
sprintf(info->result, "No memory"); return NULL; } skb_reserve(skb, 16); /* Reserve for ethernet and IP header */ eth = (__u8 *) skb_push(skb, 14); iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); /* Update any of the values, used when we're incrementing various * fields. */ mod_cur_headers(info); memcpy(eth, info->hh, 14); datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ if (datalen < sizeof(struct pktgen_hdr)) { datalen = sizeof(struct pktgen_hdr); } udph->source = htons(info->cur_udp_src); udph->dest = htons(info->cur_udp_dst); udph->len = htons(datalen + 8); /* DATA + udphdr */ udph->check = 0; /* No checksum */ iph->ihl = 5; iph->version = 4; iph->ttl = 3; iph->tos = 0; iph->protocol = IPPROTO_UDP; /* UDP */ iph->saddr = info->cur_saddr; iph->daddr = info->cur_daddr; iph->frag_off = 0; iplen = 20 + 8 + datalen; iph->tot_len = htons(iplen); iph->check = 0; iph->check = ip_fast_csum((void *) iph, iph->ihl); skb->protocol = __constant_htons(ETH_P_IP); skb->mac.raw = ((u8 *)iph) - 14; skb->dev = odev; skb->pkt_type = PACKET_HOST; if (info->nfrags <= 0) { pgh = (struct pktgen_hdr *)skb_put(skb, datalen); } else { int frags = info->nfrags; int i; /* TODO: Verify this is OK...it sure is ugly. --Ben */ pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); if (frags > MAX_SKB_FRAGS) frags = MAX_SKB_FRAGS; if (datalen > frags*PAGE_SIZE) { skb_put(skb, datalen-frags*PAGE_SIZE); datalen = frags*PAGE_SIZE; } i = 0; while (datalen > 0) { struct page *page = alloc_pages(GFP_KERNEL, 0); skb_shinfo(skb)->frags[i].page = page; skb_shinfo(skb)->frags[i].page_offset = 0; skb_shinfo(skb)->frags[i].size = (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); datalen -= skb_shinfo(skb)->frags[i].size; skb->len += skb_shinfo(skb)->frags[i].size; skb->data_len += skb_shinfo(skb)->frags[i].size; i++; skb_shinfo(skb)->nr_frags = i; } while (i < frags) { int rem; if (i == 0) break; rem = skb_shinfo(skb)->frags[i - 1].size / 2; if (rem == 0) break; skb_shinfo(skb)->frags[i - 1].size -= rem; skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1]; get_page(skb_shinfo(skb)->frags[i].page); skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page; skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size; skb_shinfo(skb)->frags[i].size = rem; i++; skb_shinfo(skb)->nr_frags = i; } } /* Stamp the time, and sequence number, convert them to network byte order */ if (pgh) { struct timeval timestamp; pgh->pgh_magic = htonl(PKTGEN_MAGIC); pgh->seq_num = htonl(info->seq_num); do_gettimeofday(×tamp); pgh->tv_sec = htonl(timestamp.tv_sec); pgh->tv_usec = htonl(timestamp.tv_usec); } return skb;}static void show_results(struct pktgen_info* info, int nr_frags){ __u64 total, bps, mbps, pps; unsigned long idle; int size = info->pkt_size + 4; /* incl 32bit ethernet CRC */ char *p = info->result; total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000ull + info->stopped_at.tv_usec - info->started_at.tv_usec; BUG_ON(cpu_speed == 0); idle = info->idle_acc; do_div(idle, cpu_speed); p += sprintf(p, "OK: %llu(c%llu+d%lu) usec, %llu (%dbyte,%dfrags)\n", total, total - idle, idle, info->sofar, size, nr_frags); pps = info->sofar * USEC_PER_SEC; while ((total >> 32) != 0) { pps >>= 1; total >>= 1; } do_div(pps, total); bps = pps * 8 * size; mbps = bps; do_div(mbps, 1000000); p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", pps, mbps, bps, info->errors);}static void inject(struct pktgen_info* info){ struct net_device *odev; struct sk_buff *skb = NULL; __u64 lcount = 0; int ret; int last_ok = 1; /* Was last skb sent? * Or a failed transmit of some sort? This will keep * sequence numbers in order, for example. */ __u64 fp = 0; __u32 fp_tmp = 0; odev = setup_inject(info); if (!odev) return; info->do_run_run = 1; /* Cranke yeself! */ info->idle_acc = 0; info->sofar = 0; lcount = info->count; /* Build our initial pkt and place it as a re-try pkt. */ skb = fill_packet(odev, info); if (skb == NULL) goto out_reldev; do_gettimeofday(&(info->started_at)); while(info->do_run_run) { /* Set a time-stamp, so build a new pkt each time */ if (last_ok) { if (++fp_tmp >= info->clone_skb ) { kfree_skb(skb); skb = fill_packet(odev, info); if (skb == NULL) { goto out_reldev; } fp++; fp_tmp = 0; /* reset counter */ } } if (!(odev->features & NETIF_F_LLTX)) spin_lock_bh(&odev->xmit_lock); if (!netif_queue_stopped(odev)) { atomic_inc(&skb->users); retry: ret = odev->hard_start_xmit(skb, odev); if (likely(ret == NETDEV_TX_OK)) { last_ok = 1; info->sofar++; info->seq_num++; } else if (ret == NETDEV_TX_LOCKED && (odev->features & NETIF_F_LLTX)) { cpu_relax(); goto retry; } else { atomic_dec(&skb->users); if (debug && net_ratelimit()) { printk(KERN_INFO "Hard xmit error\n"); } info->errors++; last_ok = 0; } } else { /* Re-try it next time */ last_ok = 0; } if (!(odev->features & NETIF_F_LLTX)) spin_unlock_bh(&odev->xmit_lock); if (info->ipg) { /* Try not to busy-spin if we have larger sleep times. * TODO: Investigate better ways to do this. */ if (info->ipg < 10000) { /* 10 usecs or less */ nanospin(info->ipg, info); } else if (info->ipg < 10000000) { /* 10ms or less */ udelay(info->ipg / 1000); } else { mdelay(info->ipg / 1000000); } } if (signal_pending(current)) { break; } /* If lcount is zero, then run forever */ if ((lcount != 0) && (--lcount == 0)) { if (atomic_read(&skb->users) != 1) { u32 idle_start, idle; idle_start = cycles(); while (atomic_read(&skb->users) != 1) { if (signal_pending(current)) { break; } schedule(); } idle = cycles() - idle_start; info->idle_acc += idle; } break; } if (netif_queue_stopped(odev) || need_resched()) { u32 idle_start, idle; idle_start = cycles(); do { if (signal_pending(current)) { info->do_run_run = 0; break; } if (!netif_running(odev)) { info->do_run_run = 0; break; } if (need_resched()) schedule(); else do_softirq(); } while (netif_queue_stopped(odev)); idle = cycles() - idle_start; info->idle_acc += idle; } }/* while we should be running */ do_gettimeofday(&(info->stopped_at)); show_results(info, skb_shinfo(skb)->nr_frags); kfree_skb(skb);out_reldev: if (odev) { dev_put(odev); odev = NULL; } return;}/* proc/net/pktgen/pg */static int proc_busy_read(char *buf , char **start, off_t offset, int len, int *eof, void *data){ char *p; int idx = (int)(long)(data); struct pktgen_info* info = NULL; if ((idx < 0) || (idx >= MAX_PKTGEN)) { printk("ERROR: idx: %i is out of range in proc_write\n", idx); return -EINVAL; } info = &(pginfos[idx]); p = buf; p += sprintf(p, "%d\n", info->busy); *eof = 1; return p-buf;}static int proc_read(char *buf , char **start, off_t offset, int len, int *eof, void *data){ char *p; int i; int idx = (int)(long)(data); struct pktgen_info* info = NULL; __u64 sa; __u64 stopped; __u64 now = getCurMs(); if ((idx < 0) || (idx >= MAX_PKTGEN)) { printk("ERROR: idx: %i is out of range in proc_write\n", idx); return -EINVAL; } info = &(pginfos[idx]); p = buf; p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */ p += sprintf(p, "Params: count %llu pkt_size: %u frags: %d ipg: %u clone_skb: %d odev \"%s\"\n", (unsigned long long) info->count, info->pkt_size, info->nfrags, info->ipg, info->clone_skb, info->outdev); p += sprintf(p, " dst_min: %s dst_max: %s src_min: %s src_max: %s\n", info->dst_min, info->dst_max, info->src_min, info->src_max); p += sprintf(p, " src_mac: "); for (i = 0; i < 6; i++) { p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? " " : ":"); } p += sprintf(p, "dst_mac: "); for (i = 0; i < 6; i++) { p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":"); } p += sprintf(p, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", info->udp_src_min, info->udp_src_max, info->udp_dst_min, info->udp_dst_max); p += sprintf(p, " src_mac_count: %d dst_mac_count: %d\n Flags: ", info->src_mac_count, info->dst_mac_count); if (info->flags & F_IPSRC_RND) { p += sprintf(p, "IPSRC_RND "); } if (info->flags & F_IPDST_RND) { p += sprintf(p, "IPDST_RND "); } if (info->flags & F_UDPSRC_RND) { p += sprintf(p, "UDPSRC_RND "); } if (info->flags & F_UDPDST_RND) { p += sprintf(p, "UDPDST_RND "); } if (info->flags & F_MACSRC_RND) { p += sprintf(p, "MACSRC_RND "); } if (info->flags & F_MACDST_RND) { p += sprintf(p, "MACDST_RND "); } p += sprintf(p, "\n"); sa = tv_to_ms(&(info->started_at)); stopped = tv_to_ms(&(info->stopped_at)); if (info->do_run_run) { stopped = now; /* not really stopped, more like last-running-at */ } p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %llums stopped: %llums now: %llums idle: %lluns\n", (unsigned long long) info->sofar, (unsigned long long) info->errors, (unsigned long long) sa, (unsigned long long) stopped, (unsigned long long) now, (unsigned long long) info->idle_acc); p += sprintf(p, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset); p += sprintf(p, " cur_saddr: 0x%x cur_daddr: 0x%x cur_udp_dst: %d cur_udp_src: %d\n", info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src); if (info->result[0]) p += sprintf(p, "Result: %s\n", info->result); else p += sprintf(p, "Result: Idle\n"); *eof = 1; return p - buf;}static int count_trail_chars(const char __user *user_buffer, unsigned int maxlen){ int i; for (i = 0; i < maxlen; i++) { char c; if (get_user(c, &user_buffer[i])) return -EFAULT; switch (c) { case '\"': case '\n': case '\r': case '\t': case ' ': case '=': break; default: goto done; }; }done: return i;}static unsigned long num_arg(const char __user *user_buffer, unsigned long maxlen, unsigned long *num){ int i = 0; *num = 0; for(; i < maxlen; i++) { char c; if (get_user(c, &user_buffer[i])) return -EFAULT; if ((c >= '0') && (c <= '9')) { *num *= 10; *num += c -'0'; } else break; } return i;}static int strn_len(const char __user *user_buffer, unsigned int maxlen){ int i = 0; for(; i < maxlen; i++) { char c; if (get_user(c, &user_buffer[i])) return -EFAULT; switch (c) { case '\"': case '\n': case '\r': case '\t': case ' ': goto done_str; default: break; }; }done_str: return i;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -