Index: pkt-gen.c =================================================================== --- pkt-gen.c (revision 313754) +++ pkt-gen.c (working copy) @@ -57,6 +60,7 @@ #include #include #include +#include #include @@ -191,15 +195,22 @@ }; #define MAX_BODYSIZE 16384 +#define MAX_LINKHDR 64 -struct pkt { +/* compat for rxseq */ +struct packet { struct virt_header vh; struct ether_header eh; struct ip ip; struct udphdr udp; - uint8_t body[MAX_BODYSIZE]; // XXX hardwired + uint8_t body[MAX_BODYSIZE]; // XXX hardwired } __attribute__((__packed__)); +struct vlan_shim { + uint16_t v_tag; + uint16_t v_proto; +} __attribute__((__packed__)); + struct ip_range { char *name; uint32_t start, end; /* same as struct in_addr */ @@ -214,8 +225,16 @@ /* ifname can be netmap:foo-xxxx */ #define MAX_IFNAMELEN 64 /* our buffer for ifname */ //#define MAX_PKTSIZE 1536 -#define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ +#define MAX_PKTSIZE (MAX_BODYSIZE + MAX_LINKHDR) +struct pkt { + uint8_t buf[MAX_PKTSIZE]; + void *frame; + struct ether_header *eh; + struct ip *ip; + uint8_t *body; +}; + /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ struct tstamp { uint32_t sec; @@ -277,6 +296,7 @@ #define STATS_WIN 15 int win_idx; int64_t win[STATS_WIN]; + uint16_t vlan_tag; }; enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; @@ -306,7 +326,6 @@ void *frame; }; - /* * extract the extremes from a range of ipv4 addresses. * addr_lo[-addr_hi][:port_lo[-port_hi]] @@ -319,7 +338,7 @@ if (verbose) D("extract IP range from %s", r->name); - r->port0 = r->port1 = 0; + r->port0 = r->port1 = 7; r->start = r->end = 0; /* the first - splits start/end of range */ @@ -647,9 +666,12 @@ { uint32_t a; uint16_t p; - struct ip *ip = &pkt->ip; - struct udphdr *udp = &pkt->udp; + struct ip *ip; + struct udphdr *udp; + ip = pkt->ip; + udp = (struct udphdr *)(ip + 1); + do { /* XXX for now it doesn't handle non-random src, random dst */ if (g->options & OPT_RANDOM_SRC) { @@ -669,8 +691,6 @@ break; } ip->ip_src.s_addr = htonl(g->src_ip.start); - - udp->uh_sport = htons(g->src_ip.port0); } if (g->options & OPT_RANDOM_DST) { @@ -689,12 +709,20 @@ ip->ip_dst.s_addr = htonl(a + 1); break; } + ip->ip_dst.s_addr = htonl(g->dst_ip.start); } - ip->ip_dst.s_addr = htonl(g->dst_ip.start); } while (0); - // update checksum + ip->ip_sum = 0; + ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0)); } +static inline void * +buf_prepend(void *cur, size_t len) +{ + uint8_t *buf = cur; + return (buf - len); +} + /* * initialize one packet and prepare for the next one. * The copy could be done better instead of repeating it each time. @@ -706,11 +734,12 @@ struct ether_header *eh; struct ip *ip; struct udphdr *udp; - uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip); + uint8_t *body; + uint16_t paylen = targ->g->pkt_size - sizeof(*eh); const char *payload = targ->g->options & OPT_INDIRECT ? indirect_payload : default_payload; int i, l0 = strlen(payload); - + #ifndef NO_PCAP char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *file; @@ -735,21 +764,34 @@ } #endif - /* create a nice NUL-terminated string */ - for (i = 0; i < paylen; i += l0) { - if (l0 > paylen - i) - l0 = paylen - i; // last round - bcopy(payload, pkt->body + i, l0); + ip = (struct ip *)(pkt->buf + MAX_LINKHDR); + + if (targ->g->vlan_tag != 0) { + struct vlan_shim *vlan; + + /* prepend shim */ + vlan = buf_prepend(ip, sizeof(*vlan)); + vlan->v_tag = htons(targ->g->vlan_tag); + vlan->v_proto = htons(ETHERTYPE_IP); + + eh = buf_prepend(vlan, sizeof(*eh)); + eh->ether_type = htons(ETHERTYPE_VLAN); + + paylen -= sizeof(*vlan); + } else { + eh = buf_prepend(ip, sizeof(*eh)); + eh->ether_type = htons(ETHERTYPE_IP); } - pkt->body[i-1] = '\0'; - ip = &pkt->ip; + memcpy(eh->ether_shost, &targ->g->src_mac.start, 6); + memcpy(eh->ether_dhost, &targ->g->dst_mac.start, 6); + /* prepare the headers */ ip->ip_v = IPVERSION; ip->ip_hl = 5; ip->ip_id = 0; ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh)); + ip->ip_len = ntohs(paylen); ip->ip_id = 0; ip->ip_off = htons(IP_DF); /* Don't fragment */ ip->ip_ttl = IPDEFTTL; @@ -756,13 +798,17 @@ ip->ip_p = IPPROTO_UDP; ip->ip_dst.s_addr = htonl(targ->g->dst_ip.start); ip->ip_src.s_addr = htonl(targ->g->src_ip.start); + ip->ip_sum = 0; ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0)); + paylen -= sizeof(*ip); - udp = &pkt->udp; + udp = (struct udphdr *)(ip + 1); udp->uh_sport = htons(targ->g->src_ip.port0); udp->uh_dport = htons(targ->g->dst_ip.port0); udp->uh_ulen = htons(paylen); + udp->uh_sum = 0; +#if 0 /* Magic: taken from sbin/dhclient/packet.c */ udp->uh_sum = wrapsum(checksum(udp, sizeof(*udp), checksum(pkt->body, @@ -772,14 +818,26 @@ ) ) )); +#endif + paylen -= sizeof(*udp); - eh = &pkt->eh; - bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); - bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); - eh->ether_type = htons(ETHERTYPE_IP); + body = (uint8_t *)(udp + 1); - bzero(&pkt->vh, sizeof(pkt->vh)); - // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); + /* create a nice NUL-terminated string */ + for (i = 0; i < paylen; i += l0) { + if (l0 > paylen - i) + l0 = paylen - i; // last round + bcopy(payload, body + i, l0); + } + body[i-1] = '\0'; + + /* stash where we put the bits to update later */ + pkt->frame = eh; + pkt->eh = eh; + pkt->ip = ip; + pkt->body = body; + + // dump_payload(eh, targ->g->pkt_size, NULL, 0); } static void @@ -927,7 +985,7 @@ struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; struct netmap_if *nifp = targ->nmd->nifp; int i, rx = 0; - void *frame; + uint8_t *frame; int size; struct timespec ts, now, last_print; uint64_t sent = 0, n = targ->g->npackets; @@ -934,11 +992,10 @@ uint64_t count = 0, t_cur, t_min = ~0, av = 0; uint64_t buckets[64]; /* bins for delays, ns */ - frame = &targ->pkt; - frame += sizeof(targ->pkt.vh) - targ->g->virt_header; + frame = targ->pkt.frame; + frame -= targ->g->virt_header; size = targ->g->pkt_size + targ->g->virt_header; - if (targ->g->nthreads > 1) { D("can only ping with 1 thread"); return NULL; @@ -957,7 +1014,7 @@ p = NETMAP_BUF(ring, slot->buf_idx); if (nm_ring_empty(ring)) { - D("-- ouch, cannot send"); + D("-- ouch, c;annot send"); } else { struct tstamp *tp; nm_pkt_copy(frame, p, size); @@ -1166,12 +1223,12 @@ struct timespec nexttime = { 0, 0}; // XXX silence compiler int rate_limit = targ->g->tx_rate; struct pkt *pkt = &targ->pkt; - void *frame; + uint8_t *frame; int size; if (targ->frame == NULL) { - frame = pkt; - frame += sizeof(pkt->vh) - targ->g->virt_header; + frame = pkt->frame; + frame -= targ->g->virt_header; size = targ->g->pkt_size + targ->g->virt_header; } else { frame = targ->frame; @@ -1491,7 +1548,7 @@ int frags = targ->g->frags; uint32_t sequence = 0; int budget = 0; - void *frame; + uint8_t *frame; int size; if (targ->g->nthreads > 1) { @@ -1503,8 +1560,8 @@ D("Ignoring -n argument"); } - frame = pkt; - frame += sizeof(pkt->vh) - targ->g->virt_header; + frame = pkt->frame; + frame -= targ->g->virt_header; size = targ->g->pkt_size + targ->g->virt_header; D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); @@ -1752,7 +1809,7 @@ struct netmap_slot *slot = &ring->slot[head]; char *p = NETMAP_BUF(ring, slot->buf_idx); int len = slot->len; - struct pkt *pkt; + struct packet *pkt; if (dump) { dump_payload(p, slot->len, ring, head); @@ -1776,7 +1833,7 @@ p -= sizeof(pkt->vh) - targ->g->virt_header; len += sizeof(pkt->vh) - targ->g->virt_header; - pkt = (struct pkt *)p; + pkt = (struct packet *)p; if ((char *)pkt + len < ((char *)pkt->body) + sizeof(seq)) { RD(1, "%s: packet too small (len=%u)", __func__, @@ -2223,8 +2280,8 @@ g.nmr_config = ""; g.virt_header = 0; - while ( (ch = getopt(arc, argv, - "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:E:m:rP:zZA")) != -1) { + while ((ch = getopt(arc, argv, + "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:E:m:rP:V:zZA")) != -1) { struct td_desc *fn; switch(ch) { @@ -2372,6 +2429,9 @@ case 'r': g.options |= OPT_RUBBISH; break; + case 'V': + g.vlan_tag = atoi(optarg); + break; case 'z': g.options |= OPT_RANDOM_SRC; break;